2. Iterator 群の作成

testCheckSameSize (ImageLibraryTests)

大きさの比較を行う checkSameSize をテストする。テストはこんな感じ。これまではあるオブジェクトに対して他と等しいかインスタンスメソッドで確認していたが、ジェネリックを使ってみたいので関数で書いてみる(二つのクラスに同じような内容を書きたくないし)。Objective-C の頃は二つのオブジェクトの比較だけをしていたが、可変長引数を使って複数個を一度に比較できるようにしてみた。すべての画像が同じ大きさの場合のみ true を返すことが確認できればよい。

    func testCheckSameSize() {
        var mcorrect1 = MonoMatrix(rnum: 2, cnum: 3)
        XCTAssertTrue(checkSameSize(mmat1!, mcorrect1))
        var mcorrect2 = MonoMatrix(rnum: 2, cnum: 3)
        XCTAssertTrue(checkSameSize(mmat1!, mcorrect1, mcorrect2))
        var mdiffer = MonoMatrix(rnum: 2, cnum: 2)
        XCTAssertFalse(checkSameSize(mmat1!, mdiffer))
        mdiffer = MonoMatrix(rnum: 1, cnum: 3)
        XCTAssertFalse(checkSameSize(mmat1!, mdiffer))
        mdiffer = MonoMatrix(rnum: 1, cnum: 2)
        XCTAssertFalse(checkSameSize(mmat1!, mdiffer))
        XCTAssertFalse(checkSameSize(mmat1!, mcorrect1, mcorrect2, mdiffer))
        
        var ccorrect1 = ColorMatrix(pnum: 3, rnum:2, cnum: 3, type: ColorType.RGB)
        XCTAssertTrue(checkSameSize(cmat1!, ccorrect1))
        var ccorrect2 = ColorMatrix(pnum: 3, rnum: 2, cnum: 3, type: ColorType.RGB)
        XCTAssertTrue(checkSameSize(cmat1!, ccorrect1, ccorrect2))
        var cdiffer = ColorMatrix(pnum: 3, rnum: 2, cnum: 2, type: ColorType.RGB)
        XCTAssertFalse(checkSameSize(cmat1!, cdiffer))
        cdiffer = ColorMatrix(pnum: 3, rnum: 1, cnum: 3, type: ColorType.RGB)
        XCTAssertFalse(checkSameSize(cmat1!, cdiffer))
        cdiffer = ColorMatrix(pnum: 3, rnum: 1, cnum: 2, type: ColorType.RGB)
        XCTAssertFalse(checkSameSize(cmat1!, cdiffer))
        XCTAssertFalse(checkSameSize(cmat1!, ccorrect1, ccorrect2, cdiffer))
    }

checkSameSize の実装 (ImageMatrix)

checkSameSize は引数に ImageMatrix を取るため、プロトコルを書いた ImageMatrix.m に記載した。
ImageMatrix は rnum, cnum に応答するので、関数内でキャストすることもなく使用可能である。初回だけ余計な比較があるが、余計なことをするとコードが汚くなるのでこのままにする。

public func checkSameSize<T:ImageMatrix>(mats: T ...) -> Bool {
    let r = mats[0].rnum
    let c = mats[0].cnum
    for m in mats {
        if r != m.rnum || c != m.cnum {
            return false
        }
    }
    return true
}

testDoubleValueAndSetDoubleValue (ImageLibraryTests)

MonoMatrix のみの機能として任意の位置の doubleValue を読み込むメソッドと、任意の位置に doubleValue を書き込むメソッドを追加する。テストは以下のように記述した。doubleValue, setDoubleValue 共に doubleValue であることがわかっているので、External Parameter Name は使わずに第一引数名は省略した。

    func testDoubleValueAndSetDoubleValue() {
        let data : [Double] = [ 3.0, 1.0, 4.0, 1.0, 5.0, 9.0 ]
        for i in 0 ..< 6 {
            XCTAssertEqual(mmat1!.doubleValue(i), data[i])
        }
        let data2 : [Double] = [ 2.0, 9.0, 4.0, 7.0, 5.0, 3.0 ]
        for i in 0 ..< 6 {
            mmat1!.setDoubleValue(data2[i], at: i)
        }
        XCTAssertEqual(mmat1!.doubleBuffer, data2)
    }

doubleValue と setDoubleValue の実装 (MonoMatrix)

MonoMatrix.swift に実装を記述する。setDoubleValue の方で変数名を揃えたかったので、at n のようにして引数名と変数名をわざと変えたことくらいが新しいところ。

    public func doubleValue(n: Int) -> Double {
        return _doubleBuffer[n]
    }
    
    public func setDoubleValue(value: Double, at n: Int) {
        _doubleBuffer[n] = value
    }

testPixelIterator (ImageLibraryTests)

画像処理では Pixel ごとの逐次処理や Block ごとの逐次処理が多く行われる。そこでこれらの Iterator 処理を行うクラスを設計する。PixelIterator では、MonoMatrix の全部もしくは一部を Pixel ごとに逐次処理する。PixelIterator オブジェクトは MonoMatrix に依存するため、直接コンストラクタは呼ばず、MonoMatrix のインスタンスメソッドで作成することにする。ここでは作成のみのテストを行う。

引数なしの場合には画像全体となり、逆に引数 wrnum, wcnum, offsetr, offsetc が設定された場合には画像の一部分を切り出す。これらの値は省略可能で省略時には画像のサイズや設定された値から計算して割り当てる。範囲が画像からはみ出ている場合には、はみ出ないギリギリのところの値を設定する。ここで、nowp は切り出した左上 Pixel の doubleBuffer 上の位置を示す。

    func testPixelIterator() {
        var pi1 : PixelIterator = mmat1!.pixelIterator() // 画像全体
        XCTAssertEqual([ pi1.wrnum, pi1.wcnum, pi1.nowp], [ 2, 3, 0 ])
        var pi2 : PixelIterator = mmat1!.pixelIterator(wrnum: 1, wcnum: 2) // 大きさのみ指定
        XCTAssertEqual([ pi2.wrnum, pi2.wcnum, pi2.nowp], [ 1, 2, 0 ])
        var pi3 : PixelIterator = mmat1!.pixelIterator(wrnum: 1, wcnum: 3, offsetr: 1) // 大きさと横オフセット
        XCTAssertEqual([ pi3.wrnum, pi3.wcnum, pi3.nowp], [ 1, 3, 3 ])
        var pi4 : PixelIterator = mmat1!.pixelIterator(wrnum: 1, wcnum: 2, offsetr: 1, offsetc: 1) // 大きさとオフセット
        XCTAssertEqual([ pi4.wrnum, pi4.wcnum, pi4.nowp], [ 1, 2, 4 ])
        var pi5 : PixelIterator = mmat1!.pixelIterator(offsetr: 1, offsetc: 2) // オフセットのみ
        XCTAssertEqual([ pi5.wrnum, pi5.wcnum, pi5.nowp], [ 1, 1, 5 ])
        var pi6 : PixelIterator = mmat1!.pixelIterator(offsetc: 2) // 横オフセットのみ
        XCTAssertEqual([ pi6.wrnum, pi6.wcnum, pi6.nowp], [ 2, 1, 2 ])
        var pi7 : PixelIterator = mmat1!.pixelIterator(wrnum: 5, wcnum: 5, offsetr: 5, offsetc: 5) // すべてはみ出る
        XCTAssertEqual([ pi7.wrnum, pi7.wcnum, pi7.nowp], [ 1, 1, 5 ]) // 右下 1 pixel だけ対象
    }

pixelIterator() の実装 (MonoMatrix)

pixelIterator() の実装については、PixelIterator のコンストラクタ呼び出しのみでよい。値が存在しなかった場合には -1 を渡し、初期化部で対応する。

    public func pixelIterator(wrnum: Int = -1, wcnum: Int = -1, offsetr: Int = -1, offsetc: Int = -1) -> PixelIterator {
        return PixelIterator(matrix: self, wrnum: wrnum, wcnum: wcnum, offsetr: offsetr, offsetc: offsetc)
    }

PixelIterator クラスの実装 (PixelIterator)

_wrnum, _wcnum, _offsetr, _offsetc は初期化時のみに値が設定されるので定数とする。_matrix は PixelIterator が生きている間は消えないので、unowned var とした。_nowr, _nowc は現在の Pixel 位置を保持する変数であるため、初期化時は 0 とする。

_offsetr, _offsetc については未指定時(負の値)の時には 0 とする。逆に画像サイズを超えている時には、画像の大きさ-1に設定する。_wrnum, _wcnum については未指定時(負の値)の時には画像サイズからオフセットを引いた値に設定する。値が指定されており画像サイズを越える時には超えない最大値を設定する。_nowr, _nowc は 0 とし、_nowp は _offsetr, _offsetc から計算する。

public class PixelIterator {
    private unowned var _matrix : MonoMatrix
    private let _wrnum, _wcnum : Int
    private let _offsetr, _offsetc : Int
    private var _nowr, _nowc, _nowp: Int
    
    public var wrnum :Int { return _wrnum }
    public var wcnum :Int { return _wcnum }
    public var nowr : Int { return _nowr }
    public var nowc : Int { return _nowc }
    public var nowp : Int { return _nowp }

    public init(matrix: MonoMatrix, wrnum: Int, wcnum: Int, offsetr: Int, offsetc: Int) {
        _matrix = matrix
        _offsetr = offsetr < 0 ? 0 : min(offsetr, _matrix.rnum - 1)
        _offsetc = offsetc < 0 ? 0 : min(offsetc, _matrix.cnum - 1)
        let tmpr = _matrix.rnum - _offsetr
        _wrnum = wrnum < 0 ? tmpr : min(wrnum, tmpr)
        let tmpc = _matrix.cnum - _offsetc
        _wcnum = wcnum < 0 ? tmpc : min(wcnum, tmpc)
        _nowr = 0
        _nowc = 0
        _nowp = _offsetr * _matrix.cnum + _offsetc
    }

testSetPos (ImageLibraryTests)

PixelIterator の setPos をテストする。これは、row, col で直接位置を指定するものである。指定により nowr, nowc, nowp の値が適切に設定されることを確認する。あまり使わない予定なので、性善説に立ち範囲外のチェックはしていない。引数なしで設定された場合には、(0, 0) に戻る。

    func testSetPos() {
        var pi1 : PixelIterator = mmat1!.pixelIterator()
        pi1.setPos(row: 0, col:1)
        XCTAssertEqual([ pi1.nowr, pi1.nowc, pi1.nowp ], [ 0, 1, 1 ])
        pi1.setPos(row: 1, col:2)
        XCTAssertEqual([ pi1.nowr, pi1.nowc, pi1.nowp ], [ 1, 2, 5 ])
        pi1.setPos()
        XCTAssertEqual([ pi1.nowr, pi1.nowc, pi1.nowp ], [ 0, 0, 0 ])
        
        var pi2 : PixelIterator = mmat1!.pixelIterator(wrnum: 1, wcnum: 2, offsetr: 1, offsetc: 1)
        pi2.setPos(row: 0, col:1)
        XCTAssertEqual([ pi2.nowr, pi2.nowc, pi2.nowp ], [ 0, 1, 5 ])
        pi2.setPos()
        XCTAssertEqual([ pi2.nowr, pi2.nowc, pi2.nowp ], [ 0, 0, 4 ])
    }

setPos の実装 (PixelIterator)

範囲チェックはしないので、そのまま実装する。

    public func setPos(row: Int = 0, col: Int = 0) {
        _nowr = row
        _nowc = col
        _nowp = (_nowr + _offsetr) * _matrix.cnum + (_nowc + _offsetc)
    }

testNextPI (ImageLibraryTests)

PixelIterator 用の nextPos のテストを行う。finished になっていなければ、次の値に移動する。finished かどうかは nowp の値が -1 になっているかどうかで判断する。画像全体の場合と、一部切り出しの両方で確認を行っている。

    func testNextPosPI() {
        var pi1 = mmat1!.pixelIterator()
        XCTAssertFalse(pi1.finished)
        pi1.nextPos()
        XCTAssertFalse(pi1.finished)
        XCTAssertEqual([ pi1.nowr, pi1.nowc, pi1.nowp ], [ 0, 1, 1 ])
        pi1.nextPos()
        XCTAssertFalse(pi1.finished)
        XCTAssertEqual([ pi1.nowr, pi1.nowc, pi1.nowp ], [ 0, 2, 2 ])
        pi1.nextPos()
        XCTAssertFalse(pi1.finished)
        XCTAssertEqual([ pi1.nowr, pi1.nowc, pi1.nowp ], [ 1, 0, 3 ])
        pi1.nextPos()
        XCTAssertFalse(pi1.finished)
        XCTAssertEqual([ pi1.nowr, pi1.nowc, pi1.nowp ], [ 1, 1, 4 ])
        pi1.nextPos()
        XCTAssertFalse(pi1.finished)
        XCTAssertEqual([ pi1.nowr, pi1.nowc, pi1.nowp ], [ 1, 2, 5 ])
        pi1.nextPos()
        XCTAssertTrue(pi1.finished)
        XCTAssertEqual([ pi1.nowr, pi1.nowc, pi1.nowp ], [ 0, 0, -1 ])
        pi1.nextPos()
        XCTAssertTrue(pi1.finished)
        XCTAssertEqual([ pi1.nowr, pi1.nowc, pi1.nowp ], [ 0, 0, -1 ])
        
        var pi2 = mmat1!.pixelIterator(wrnum: 1, wcnum: 2, offsetr: 1, offsetc: 1)
        XCTAssertFalse(pi2.finished)
        pi2.nextPos()
        XCTAssertFalse(pi2.finished)
        XCTAssertEqual([ pi2.nowr, pi2.nowc, pi2.nowp ], [ 0, 1, 5 ])
        pi2.nextPos()
        XCTAssertTrue(pi2.finished)
        XCTAssertEqual([ pi2.nowr, pi2.nowc, pi2.nowp ], [ 0, 0, -1 ])
        pi2.nextPos()
        XCTAssertTrue(pi2.finished)
        XCTAssertEqual([ pi2.nowr, pi2.nowc, pi2.nowp ], [ 0, 0, -1 ])
    }

nextPos の実装 (PixelIterator)

finished は computed property で _nowp が -1 かどうかを判断する。また、nextPos() は _nowc と _nowp を進め、右端まで行ったら _nowc を戻し、_nowr と _nowp を進める。下端まで行ったら _nowr も初期化し、_nowp を -1 とする。

    public var finished : Bool { return _nowp == -1 }

    public func nextPos() {
        if !finished {
            _nowc++
            _nowp++
            if _nowc == _wcnum {
                _nowc = 0
                _nowr++
                _nowp -= _wcnum
                _nowp += _matrix.cnum
                if _nowr == _wrnum {
                    _nowr = 0
                    _nowp = -1
                }
            }
        }
    }

testDoubleValuePI (ImageLibraryTests)

PixelIterator を経由して、元の MonoMatrix 画像の Pixel 値を取得・設定する。doubleValue で現在位置の pixel 値を読み込み、doubleValue = で pixel 値を書き込む。nextPos() と組み合わせることで二重ループを作ることなく、全画素にアクセスできている。

    func testDoubleValuePI() {
        let preData : [Double] = [ 3.0, 1.0, 4.0, 1.0, 5.0, 9.0 ]
        let postData : [Double] = [ 2.0, 9.0, 4.0, 7.0, 5.0, 3.0 ]
        var pi1 = mmat1!.pixelIterator()
        for i in 0 ..< 6 {
            XCTAssertEqual(pi1.doubleValue, preData[i])
            pi1.doubleValue = postData[i]
            pi1.nextPos()
        }
        XCTAssertEqual(mmat1!.doubleBuffer, postData)
    }

doubleValue の実装 (PixelIterator)

doubleValue は computed property で実現できる。ここで始めて setter と getter が出てきた(これまでのは getter のみだったので省略記述だけだった)。getter は get {} 内に記載し、setter は set {} 内に記載する。setter でセットする値は newValue という変数で与えられるので、これを MonoMatrix の setDoubleValue:at に渡せばよい。

    public var doubleValue : Double {
        get {
            return _matrix.doubleValue(_nowp)
        }
        set {
            _matrix.setDoubleValue(newValue, at: _nowp)
        }
    }

testBlockIterator (ImageLibraryTests)

PixelIterator は pixel 単位での Iterator だったが、BlockIterator はブロック単位の Iterator となる。ブロックサイズ(brnum, bcnum)と移動幅(srnum, scnum)は独立して設定できるようにする。例えばブロックごとの DCT 変換であれば brnum, bcnum, srnum, scnum はすべて 8 にするが、ブロックマッチングなどの場合だと brnum, bcnum は 8 に設定し、srnum, scnum を 1 に設定する。fixSize フラグはブロックサイズが固定かどうかを示すもので、true の場合には右端・下端のブロック幅に満たない pixel は無視される。逆に false の場合には、ブロックサイズを小さくして対応する。

BlockIterator に対して pixelIterator() を呼び出すと、対象としているブロックに対して PixelIterator を作成する。nextPos() は srnum, scnum, fixSize に従って次のブロックに進める作業をする。これらを一括でテストしたので、以下のようにかなり大きいテストになった。

    func testBlockIterator() {
        var mat2 = MonoMatrix(rnum: 4, cnum: 8);
        var bi1 : BlockIterator = mat2.blockIterator(brnum: 2, bcnum: 4, srnum: 2, scnum: 4, fixSize: true);
        XCTAssertFalse(bi1.finished)
        XCTAssertEqual([ bi1.nowr, bi1.nowc, bi1.nowp, bi1.brnum, bi1.bcnum ], [ 0, 0, 0, 2, 4 ])
        var pi1 : PixelIterator? = bi1.pixelIterator()
        XCTAssertEqual([ pi1!.nowr, pi1!.nowc, pi1!.nowp ], [ 0, 0, 0 ])
        //
        bi1.nextPos()
        XCTAssertFalse(bi1.finished)
        XCTAssertEqual([ bi1.nowr, bi1.nowc, bi1.nowp, bi1.brnum, bi1.bcnum ], [ 0, 4, 4, 2, 4 ])
        pi1 = bi1.pixelIterator()
        XCTAssertEqual([ pi1!.nowr, pi1!.nowc, pi1!.nowp ], [ 0, 0, 4 ])
        //
        bi1.nextPos()
        XCTAssertFalse(bi1.finished)
        XCTAssertEqual([ bi1.nowr, bi1.nowc, bi1.nowp, bi1.brnum, bi1.bcnum ], [ 2, 0, 16, 2, 4 ])
        pi1 = bi1.pixelIterator()
        XCTAssertEqual([ pi1!.nowr, pi1!.nowc, pi1!.nowp ], [ 0, 0, 16 ])
        //
        bi1.nextPos()
        XCTAssertFalse(bi1.finished)
        XCTAssertEqual([ bi1.nowr, bi1.nowc, bi1.nowp, bi1.brnum, bi1.bcnum ], [ 2, 4, 20, 2, 4 ])
        pi1 = bi1.pixelIterator()
        XCTAssertEqual([ pi1!.nowr, pi1!.nowc, pi1!.nowp ], [ 0, 0, 20 ])
        //
        bi1.nextPos()
        XCTAssertTrue(bi1.finished)
        XCTAssertEqual([ bi1.nowr, bi1.nowc, bi1.nowp, bi1.brnum, bi1.bcnum ], [ 0, 0, -1, 2, 4 ])
        XCTAssertTrue(bi1.pixelIterator() == nil)
        XCTAssertTrue(bi1.finished)
        XCTAssertEqual([ bi1.nowr, bi1.nowc, bi1.nowp, bi1.brnum, bi1.bcnum ], [ 0, 0, -1, 2, 4 ])
        XCTAssertTrue(bi1.pixelIterator() == nil)

        var bi2 : BlockIterator = mat2.blockIterator(brnum: 3, bcnum: 5, srnum: 2, scnum: 4, fixSize: false);
        XCTAssertFalse(bi2.finished)
        XCTAssertEqual([ bi2.nowr, bi2.nowc, bi2.nowp, bi2.brnum, bi2.bcnum ], [ 0, 0, 0, 3, 5 ])
        var pi2 : PixelIterator? = bi2.pixelIterator()
        XCTAssertEqual([ pi2!.nowr, pi2!.nowc, pi2!.nowp ], [ 0, 0, 0 ])
        //
        bi2.nextPos()
        XCTAssertFalse(bi2.finished)
        XCTAssertEqual([ bi2.nowr, bi2.nowc, bi2.nowp, bi2.brnum, bi2.bcnum ], [ 0, 4, 4, 3, 4 ])
        pi2 = bi2.pixelIterator()
        XCTAssertEqual([ pi2!.nowr, pi2!.nowc, pi2!.nowp ], [ 0, 0, 4 ])
        //
        bi2.nextPos()
        XCTAssertFalse(bi2.finished)
        XCTAssertEqual([ bi2.nowr, bi2.nowc, bi2.nowp, bi2.brnum, bi2.bcnum ], [ 2, 0, 16, 2, 5 ])
        pi2 = bi2.pixelIterator()
        XCTAssertEqual([ pi2!.nowr, pi2!.nowc, pi2!.nowp ], [ 0, 0, 16 ])
        //
        bi2.nextPos()
        XCTAssertFalse(bi2.finished)
        XCTAssertEqual([ bi2.nowr, bi2.nowc, bi2.nowp, bi2.brnum, bi2.bcnum ], [ 2, 4, 20, 2, 4 ])
        pi2 = bi2.pixelIterator()
        XCTAssertEqual([ pi2!.nowr, pi2!.nowc, pi2!.nowp ], [ 0, 0, 20 ])
        //
        bi2.nextPos()
        XCTAssertTrue(bi2.finished)
        XCTAssertEqual([ bi2.nowr, bi2.nowc, bi2.nowp, bi2.brnum, bi2.bcnum ], [ 0, 0, -1, 3, 5 ])
        XCTAssertTrue(bi2.pixelIterator() == nil)
        bi2.nextPos()
        XCTAssertTrue(bi2.finished)
        XCTAssertEqual([ bi2.nowr, bi2.nowc, bi2.nowp, bi2.brnum, bi2.bcnum ], [ 0, 0, -1, 3, 5 ])
        XCTAssertTrue(bi2.pixelIterator() == nil)
    }

blockIterator() の実装 (MonoMatrix)

MonoMatrix に対する blockIterator() の実装はほぼ pixelIterator() と同じ。こちらはデフォルト値がないので、最初の brnum という引数名は実際にはいらない。ただし、pixelIterator() との対称性が悪くなるので、こちらでは # をわざとつけて External Parameter Name にした。

    public func blockIterator(#brnum: Int, bcnum: Int, srnum: Int, scnum: Int, fixSize: Bool) -> BlockIterator {
        return BlockIterator(matrix: self, brnum: brnum, bcnum: bcnum, srnum: srnum, scnum: scnum, fixSize: fixSize);
    }

BlockIterator クラスの実装

BlockIterator はほぼ PixelIterator と同じ構造。_matrix を unowned var とし、_brnum, _bcnum, _srnum, _scnum は定数とした。_nowr, _nowc, _nowp はすべて初期値 0 の変数としている。ここで brnum, bcnum は実際のブロックの大きさを computed property によって返すようになっており、_fixSize でない場合には定数で保持されている _brnum, _bcnum よりも小さい値が計算されるようになっている。

public class BlockIterator {
    private unowned var _matrix : MonoMatrix
    private let _brnum, _bcnum, _srnum, _scnum: Int
    private let _fixSize: Bool
    private var _nowr, _nowc, _nowp : Int
    public var brnum : Int {
        return _fixSize ? _brnum : min(_brnum, _matrix.rnum - _nowr)
    }
    public var bcnum : Int {
        return _fixSize ? _bcnum : min(_bcnum, _matrix.cnum - _nowc)
    }
    public var srnum : Int { return _srnum }
    public var scnum : Int { return _scnum }
    public var fixSize : Bool { return _fixSize }
    public var finished : Bool { return _nowp == -1 }
    public var nowr : Int { return _nowr }
    public var nowc : Int { return _nowc }
    public var nowp : Int { return _nowp }
    
    public init(matrix: MonoMatrix, brnum: Int, bcnum: Int, srnum: Int, scnum: Int, fixSize: Bool) {
        _matrix = matrix
        _brnum = brnum
        _bcnum = bcnum
        _srnum = srnum
        _scnum = scnum
        _fixSize = fixSize
        _nowr = 0
        _nowc = 0
        _nowp = 0
    }

nextPos() の実装は以下のようになる。PixelIterator の nextPos() とほぼ同内容だが、_fixSize の値により右端・下端を使うかどうかが異なっている。

    public func nextPos() {
        if !finished {
            _nowc += _scnum
            _nowp += _scnum
            if (_fixSize ? _nowc + _bcnum : _nowc + 1) > _matrix.cnum {
                _nowp -= _nowc
                _nowc = 0
                _nowr += _srnum
                _nowp += _srnum * _matrix.cnum
                if (_fixSize ? _nowr + _brnum : _nowr + 1) > _matrix.rnum {
                    _nowc = 0
                    _nowr = 0
                    _nowp = -1
                }
            }
        }
    }

pixelIterator() の実装は、computed property の brnum, bcnum があるおかげで非常に簡単にかける。

    public func pixelIterator() -> PixelIterator? {
        if !finished {
            return _matrix.pixelIterator(wrnum: brnum, wcnum: bcnum, offsetr: _nowr, offsetc: _nowc)
        } else {
            return nil
        }
    }

長くなったので今日はここまで。