座標の回転

# 座標の回転
## 基本的な考え方
中心から放射状に線を引いて基本的な回転の仕方を演習します
線の長さ x cos(角度)したものが回転後の横座標です
線の長さ x sin(角度)したものが回転後の縦座標です
算出した座標に中心座標を加算して表示位置を調整します。

## 放射状に線を引いてみる

``` python3
import math
import matplotlib
import matplotlib.pyplot as plt
import numpy as np
import PIL.Image
import PIL.ImageDraw
import random

def create_image(w, h):
    im = PIL.Image.new("RGB", (w, h), (0, 0, 0))
    return im
WIDTH = 300
HEIGHT = 200
img = create_image(WIDTH, HEIGHT)
draw = PIL.ImageDraw.Draw(img)

# π を３２分割してラジアンの配列で扱う
splitN = 32
radArr = []
for n in range(splitN):
    rad = -math.pi + (n / splitN * math.pi * 2)
    radArr.append(rad)

print(radArr)
# ラジアンの配列を８分割して内容を確認する
for i in range(0, len(radArr), int(len(radArr) / 8)):
    print("radArr[{}]={}".format(i, radArr[i]))
CENTER_X = WIDTH / 2
CENTER_Y = HEIGHT / 2
LENGTH = 10
for rad in radArr:
    x1 = CENTER_X
    y1 = CENTER_Y
    x2 = x1 + math.cos(rad) * LENGTH
    y2 = y1 + math.sin(rad) * LENGTH
    draw.line((x1, y1, x2, y2), fill=(255, 255, 255), width=1)
    LENGTH += 3 # 角度が変わる毎に長さを加算して角度の増える回転向きを確認しやすくしている

imgnp = np.array(img.convert('1')).astype(int)
plt.imshow(imgnp)
plt.show()
```

出力結果

```
[-3.141592653589793, -2.945243112740431, -2.748893571891069, -2.552544031041707, -2.356194490192345, -2.1598449493429825, -1.9634954084936207, -1.7671458676442586, -1.5707963267948966, -1.3744467859455345, -1.1780972450961724, -0.9817477042468106, -0.7853981633974483, -0.589048622548086, -0.39269908169872414, -0.1963495408493623, 0.0, 0.1963495408493623, 0.39269908169872414, 0.589048622548086, 0.7853981633974483, 0.9817477042468106, 1.178097245096172, 1.3744467859455343, 1.5707963267948966, 1.7671458676442588, 1.9634954084936211, 2.1598449493429825, 2.356194490192345, 2.552544031041707, 2.7488935718910685, 2.945243112740431]
radArr[0]=-3.141592653589793
radArr[4]=-2.356194490192345
radArr[8]=-1.5707963267948966
radArr[12]=-0.7853981633974483
radArr[16]=0.0
radArr[20]=0.7853981633974483
radArr[24]=1.5707963267948966
radArr[28]=2.356194490192345
```

![放射状の線.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104691/d985824d-32c7-45e8-8403-3da720f10d16.png)

角度が一段階変わる毎に線の長さを伸ばしてラジアンの値と見た目の角度をわかりやすくしています


## 適当な図形（複数の線）を回転させてみる - サンプル作り

``` python3
random.seed(0)
coord1 = (
    int(random.uniform(0, WIDTH)),
    int(random.uniform(0, HEIGHT)),
    int(random.uniform(0, WIDTH)),
    int(random.uniform(0, HEIGHT)),
)
coord2 = (
    int(random.uniform(0, WIDTH)),
    int(random.uniform(0, HEIGHT)),
    int(random.uniform(0, WIDTH)),
    int(random.uniform(0, HEIGHT)),
)
coord3 = (
    int(random.uniform(0, WIDTH)),
    int(random.uniform(0, HEIGHT)),
    int(random.uniform(0, WIDTH)),
    int(random.uniform(0, HEIGHT)),
)
img = create_image(WIDTH, HEIGHT)
draw = PIL.ImageDraw.Draw(img)
draw.line(coord1, fill=(255, 255, 255), width=1)
draw.line(coord2, fill=(255, 255, 255), width=1)
draw.line(coord3, fill=(255, 255, 255), width=1)
imgnp = np.array(img.convert('1')).astype(int)
plt.imshow(imgnp, cmap='binary', interpolation='nearest')
plt.show()
```
![回転対称サンプル画像.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104691/fdd5dc28-d653-7233-6dcf-529d871e843a.png)

## 作った図形を回転させる

``` python3
# 座標回転する機能を関数化しておく
def rotateCoordinate(centerX, centerY, x, y, rad):
    origRad = math.atan2(centerY - y, centerX - x) # 原点から座標の角度を出しておく（現在の角度）
    rad = origRad + rad # 現在の角度に新しい角度を加算する
    if rad > math.pi:
        rad = rad - math.pi * 2
    distance = math.sqrt((x - centerX) ** 2 + (y - centerY) ** 2)
    newX = centerX + math.cos(rad) * distance
    newY = centerY + math.sin(rad) * distance
    return newX, newY

# 対角線の幅を算出
diagonalWidth = math.ceil(math.sqrt(WIDTH ** 2 + HEIGHT ** 2))
print("diagonalWidth", diagonalWidth)
NEW_CENTER_X = int(diagonalWidth / 2)
NEW_CENTER_Y = int(diagonalWidth / 2)
#画像幅が変わるため中心に寄せるための補正値を算出
CENTER_X_DIFF = NEW_CENTER_X - CENTER_X
CENTER_Y_DIFF = NEW_CENTER_Y - CENTER_Y
img = create_image(diagonalWidth, diagonalWidth)
draw = PIL.ImageDraw.Draw(img)

rad = radArr[23]
for coord in [coord1, coord2, coord3]:
    x1, y1 = rotateCoordinate(CENTER_X, CENTER_Y, coord[0], coord[1], rad)
    x2, y2 = rotateCoordinate(CENTER_X, CENTER_Y, coord[2], coord[3], rad)
    x1 += CENTER_X_DIFF
    y1 += CENTER_Y_DIFF
    x2 += CENTER_X_DIFF
    y2 += CENTER_Y_DIFF
    print((x1, y1, x2, y2))
    draw.line((x1, y1, x2, y2), fill=(255, 255, 255), width=1)

imgnp = np.array(img.convert('1')).astype(int)
plt.figure(dpi=100)
plt.imshow(imgnp, cmap='binary', interpolation='nearest')
plt.show()
```

出力結果

```
diagonalWidth 361
(209.9257461329035, 69.0295096956447, 136.62368898862877, 213.09827250846783)
(159.79902342588701, 180.95945059911287, 124.18591141249983, 104.43686404637057)
(197.2532870625807, 184.72483709096778, 156.19898071403233, 60.344195790805884)
```

![サンプル画像_回転後.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104691/f421afc5-1d77-02fe-7e92-316ec429158e.png)

回転後にはみ出ないように元画像サイズの対角線を縦横の長さにした新しい画像素体を準備しそこに描画します。
新しい幅に対して中心がずれるため CENTER_X_DIFF, CENTER_Y_DIFF 変数にて座標の補正を行います。



以上です