PIL / 任意の排列座標を中心に、任意の排列座標を回転させる

import matplotlib.pyplot as plt
import numpy as np

def rotRC(rad, RC, centerRC=[0.0, 0.0]):
    
    COS = np.cos(rad)
    SIN = np.sin(rad)

    centerRC = np.array(centerRC)
    RC       = np.array(RC)

    # 座標の取りかたを数学座標(x, y)ではなく排列座標[行番号, 列番号]すなわち(-y , x)にしているので回転行列もそれに合わせて変えてある。
    rotMat   = np.array([[ COS, SIN], 
                         [-SIN, COS]])

    shiftedRC = RC - centerRC      # 回転中心を一旦原点[0行目, 0列目]にずらして、
    rotatedRC = shiftedRC @ rotMat # 回転行列を適用して座標を回転させて、

    # 元の回転中心に戻して、返す。
    return (rotatedRC + centerRC)#.round(0).astype("int16")

########
# test #
########
if __name__ == "__main__":
    Pi = np.pi
    
    # この4つの排列座標[行番号, 列番号]を、
    Verts = np.array([[-5, -5], [10, -5], [10, 40], [-5, 40]])

    # この排列座標[行番号, 列番号]を中心に、
    CenterRC = [-10, 20]

    # この角度だけ左に回してみる。
    Rad = (1/2)*Pi

    rotatedVerts = rotRC(Rad, Verts, CenterRC)#.round(0).astype("int16")
    print(rotatedVerts)

    ax = plt.axes(ylim=(20,-40), xlim=(-10,50))
    ax.set_aspect("equal")

    plt.scatter(      CenterRC[1],       CenterRC[0], c="black", marker="x")
    plt.scatter(       Verts[:,1],        Verts[:,0], c="blue")
    plt.scatter(rotatedVerts[:,1], rotatedVerts[:,0], c="red")
    
    plt.xlabel("col")
    plt.ylabel("row")

    plt.grid()
    plt.show()

実行結果:
f:id:ti-nspire:20181009081518p:plain:w300

PIL / 2次元排列の全要素のインデックスを収容した3次元排列を作る

2次元排列の先頭、末尾のインデックス(負数を許容)を指定することにより、全要素のインデックスを収容した3次元排列を作ることを考える。forループを使えば簡単に出来るが使わない。
(追記: numpy.where()という函数があった(2018年12月6日))

f:id:ti-nspire:20181006085809p:plain:w400

import numpy as np

def matRC(fromRC, toRC):
    # 先頭座標、末尾座標をndarrayにし、念のため整数に四捨五入しておく。
    fromRC, toRC = np.array([fromRC, toRC]).round(0).astype("int16")

    # 作成する排列の行数(高さ)、列数(幅)を取得しておく。
    numOfRows, numOfCols = (toRC - fromRC) + 1

    # 作成する排列と同じサイズの空排列を作っておく。
    mat = np.empty([numOfRows, numOfCols, 2]).astype("int16")

    # 行座標を代入する
    mat[:,:,0] = np.arange(fromRC[0], toRC[0]+1).reshape(numOfRows, 1)

    # 列座標を代入する
    mat[:,:,1] = np.arange(fromRC[1], toRC[1]+1)

    return mat
    
########
# test #
########
if __name__ == "__main__":
    print(matRC(fromRC=[-2,-1], toRC=[3, 4]))

実行結果(整形した):
f:id:ti-nspire:20181006090452p:plain:w400

PIL / 回転させた矩形がぴったり収まる背景矩形の寸法を求める

f:id:ti-nspire:20181004182909p:plain:w400

いわゆる回転行列を応用する。第1象限の中だけで行ったり来たりするよう(xy両軸を中心にミラーリングされるよう)工夫する。

import numpy as np
import matplotlib.pyplot as plt

def expandRC(rad, rows, cols):

    COS, SIN = np.abs([np.cos(rad), np.sin(rad)])
    
    matCoord = np.array([rows, cols])
    matRot   = np.array([[COS, SIN],
                         [SIN, COS]])

    # [背景矩形の高さ, 背景矩形の幅]を返す。
    return (matCoord @ matRot)#.round(0).astype("uint16")


########
# test #
########
if __name__ == "__main__":
    
    # 高さ10、幅20の矩形を回転させてみる。
    ROWs = 10
    COLs = 20

    numOfDiv = 2**6
    Pi = np.pi

    rads = np.linspace(-Pi, Pi, numOfDiv + 1)
    rows = []
    cols = []

    for rad in rads:
        rc = expandRC(rad, ROWs, COLs)
        rows.append(rc[0])
        cols.append(rc[1])

    plt.plot(rads, rows, label="rows")
    plt.plot(rads, cols, label="cols")

    plt.xlabel("rad")
    plt.ylabel("rows & cols")

    plt.legend()
    
    plt.xticks(np.round(rads[::int(numOfDiv / 8)], 2))

    plt.grid()
    plt.show()

実行結果:
f:id:ti-nspire:20181004185038p:plain:w400