SenseHAT でお絵かきアプリ

またRaspberryPiですが、今度はお絵かきアプリを作ってみました。折れ線（Polyline）をつないで絵を描きます。ジョイスティックでカーソルを移動し、ボタンを押すと、そこを折れ点とし、さらに伸ばす、を繰り返します。

[ななめの描き方のアルゴリズム](https://ja.wikipedia.org/wiki/%E3%83%96%E3%83%AC%E3%82%BC%E3%83%B3%E3%83%8F%E3%83%A0%E3%81%AE%E3%82%A2%E3%83%AB%E3%82%B4%E3%83%AA%E3%82%BA%E3%83%A0)があるみたいですね。一応それらしく実装してみましたが…まあご覧の通りです。

<img width="400" alt="drawpoly1.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/238815/695825db-7df1-d955-6cac-bcf048e7aba8.jpeg">

そう言えば、`signal.pause()`を今回初めて知りました。いいですね〜。


```python
# sensehatutil.py
from sense_hat import SenseHat, ACTION_PRESSED, ACTION_HELD, ACTION_RELEASED
import numpy as np
from enum import Enum

red = (255, 0, 0)
blue = (0, 0, 255)
yellow=(255,255,0)
purple=(128,0,128)
green=(0,255,0)
indigg=(75,0,130)
orange=(255,128,0)
pink=(255,193,203)
black=(0,0,0)

height = 8
width = 8

sense = SenseHat()

def Initialize():
    sense.clear()
    sense.set_rotation(0)

def CreateImageArray():
    return np.zeros((height, width, 3), np.uint8)

def SetArrayToPixels(imageArray):
    sense.set_pixels(imageArray.reshape(height*width,3))

def PutVertex(imageArray, pt, color):
    imageArray[pt[1], pt[0]] = color
    return imageArray

def PutRect(imageArray, lower, upper, color):
    for col in range(lower[0], upper[0]+1):
        imageArray[lower[1]:upper[1]+1, col] = color
    return imageArray

def PutLine(imageArray, p1, p2, color):
    if abs(p1[0]-p2[0]) > abs(p1[1]-p2[1]):
        if p1[0] == p2[0]:
            rs = min(p1[1], p2[1])
            re = max(p1[1], p2[1]) + 1
            imageArray[rs:re, p1[0]] = color
            return imageArray
        def f(x):
            return (float(p2[1])-float(p1[1]))/(float(p2[0])-float(p1[0]))*(float(x)-float(p1[0]))+float(p1[1])
        col_range = range(min(p1[0], p2[0]), max(p1[0], p2[0])+1)
        for col in col_range:
            row = int(round(f(col)))
            imageArray[row, col] = color
    else:
        if p1[1] == p2[1]:
            cs = min(p1[0], p2[0])
            ce = max(p1[0], p2[0]) + 1
            imageArray[p1[1], cs:ce] = color
            return imageArray
        def f(y):
            return (float(p2[0])-float(p1[0]))/(float(p2[1])-float(p1[1]))*(float(y)-float(p1[1]))+float(p1[0])
        row_range = range(min(p1[1], p2[1]), max(p1[1], p2[1])+1)
        for row in row_range:
            col = int(round(f(row)))
            imageArray[row, col] = color

    return imageArray

def PutPolyline(imageArray, ptArray, doClose, color):
    p1 = []
    p_prev = []
    for pt in ptArray:
        if p1 == []:
            p1 = pt
            p_prev = pt
            continue
        
        imageArray = PutLine(imageArray, p_prev, pt, color)
        p_prev = pt
    if doClose:
        imageArray = PutLine(imageArray, p_prev, p1, color)
    return imageArray
```

```python
# main.py
from signal import pause
import sensehatutil as sh

sh.Initialize()

apex = (3,3)
ptArray = list()

def AddApex(event):
    global apex, ptArray
    if event.action != sh.ACTION_PRESSED:
        return
    ptArray.append(apex)

def MoveApex(event):
    global apex
    if event.action != sh.ACTION_PRESSED:
        return
    d = event.direction
    if d == 'right':
        apex = (min(apex[0] + 1, sh.width-1), apex[1])
    elif d == 'left':
        apex = (max(apex[0] - 1, 0), apex[1])
    elif d == 'up':
        apex = (apex[0], max(apex[1] - 1, 0))
    elif d == 'down':
        apex = (apex[0], min(apex[1] + 1, sh.height-1))

def Reflesh():
    global apex, ptArray
    img = sh.CreateImageArray()
    ptArrayTmp = list()
    for pt in ptArray:
        ptArrayTmp.append(pt)
    ptArrayTmp.append(apex)
    img = sh.PutPolyline(img, ptArrayTmp, False, sh.orange)
    for pt in ptArray:
        img = sh.PutVertex(img, pt, sh.purple)
    img = sh.PutVertex(img, apex, sh.red)
    sh.SetArrayToPixels(img)

sh.sense.stick.direction_middle = AddApex
sh.sense.stick.direction_right = MoveApex
sh.sense.stick.direction_left = MoveApex
sh.sense.stick.direction_up = MoveApex
sh.sense.stick.direction_down = MoveApex
sh.sense.stick.direction_any = Reflesh

Reflesh()
pause()
```