iOSで指先またはペン先の動きを記録

おそらくお絵描きソフト的なコードを描いた事のある人なら、デバイスの上を指でなぞったポイントで表示するというのは、その実装が複雑または面倒になるにしたがって、恐ろしく（？）面倒な行程だと思うに違いありません。特に試行錯誤を続けているときは、コードを少し変更して、実行させて、画面を指でなぞって、確認して…とやっぱり面倒です。

さらに Apple Pencil などをサポートしようとすると、座標の他にもペンの強さや角度など様々な情報が付随し、これらも処理しようとすると、Simulator では実行できないので、実機で試行錯誤するしかなく、開発効率がなかなか上がらないと考えている人も少なくないかと思います。

また、テストの場合でも、再現可能なテストデータとしてあらかじめ用意しておく事も可能ですし、バグなどの再現の為に応用する事も考えられると思います。そもそも、同じ操作を二度繰り返す事は至難の技を通り過ぎて不可能といっても過言ではありません。

そこで今回はそんな指の動きを記録し保存する iOS のプロジェクトを公開いたしました。

#### Touch Coder
https://github.com/codelynx/TouchCoder

## 記録される情報

UITouch のプロパティとして記録されるのは以下の通りです。timestamp は 最初のタッチからの経過時間を記録します。これらの UITouch の記録はユーザーの指示で、Swift のコードとして export する事ができます。その際 CGPoint や CGVector は Tuple として export します。

| Name | Type | Description (based on UITouch documentation) |
|:-----|:-----|:------------|
| touchType | Int | 0: direct, 1: indirect, 2: stylus |
| location | (CGFloat, CGFloat) | Returns the current location of the receiver in the coordinate system of the given view.  |
| preciseLocation | (CGFloat, CGFloat) | Returns a precise location for the touch, when available. |
| majorRadius | CGFloat | The radius (in points) of the touch |
| majorRadiusTolerance | CGFloat | The tolerance (in points) of the touch’s radius. |
| timestamp| TimeInterval | The elapsed time (in seconds) from the first touch. |
| phase | UITouchPhase | The phase of the touch |
| force | CGFloat | The force of the touch, where a value of 1.0 represents the force of an average touch (predetermined by the system, not user-specific). |
| maximumPossibleForce | CGFloat | The maximum possible force for a touch. |
| altitudeAngle | CGFloat | The altitude (in radians) of the stylus. |
| azimuthAngle | CGFloat | Returns the azimuth angle (in radians) of the stylus. |
| azimuthUnitVector | (CGFloat, CGFloat) | Returns a unit vector that points in the direction of the azimuth of the stylus. |

## 出力例

以下に ひらがなの「あ」を Apple Pencil で書いた時の出力例を示します。複数のストロークで構成されているので、二次元配列になっています。一部中間を割愛させていただいています。

```swift:あ
typealias Point = (
	touchType: Int, location: (CGFloat, CGFloat), preciseLocation: (CGFloat, CGFloat), majorRadius: CGFloat, majorRadiusTolerance: CGFloat, timestamp: TimeInterval, 
	force: CGFloat, maximumPossibleForce: CGFloat, altitudeAngle: CGFloat, azimuthAngle: CGFloat, azimuthUnitVector: (CGFloat, CGFloat) 
)

[[	Point(2, (355.03125, 684.459045410156), (355.03125, 684.459045410156), 0.25, 0.0, 0.0, 0.333333333333333,4.16666666666667, 0.793895081677709, 1.04037475585938, (0.505897030655754, 0.862593875687563)), 
	Point(2, (355.296875, 683.854614257812), (355.296875, 683.854614257812), 0.25, 0.0, 0.0129999999990105, 0.2078125,4.16666666666667, 0.793895081677709, 1.04037475585938, (0.505897030655754, 0.862593875687563)), 
	Point(2, (355.5625, 683.39599609375), (355.5625, 683.39599609375), 0.25, 0.0, 0.0169999999998254, 0.145052083333333,4.16666666666667, 0.793895081677709, 1.04037475585938, (0.505897030655754, 0.862593875687563)), 
	Point(2, (355.703125, 683.125061035156), (355.703125, 683.125061035156), 0.25, 0.0, 0.0210000000006403, 0.113671875,4.16666666666667, 0.793895081677709, 1.04037475585938, (0.505897030655754, 0.862593875687563)),
	...
Point(2, (477.71875, 651.880615234375), (477.71875, 651.880615234375), 0.25, 0.0, 0.26299999999901, 0.0,4.16666666666667, 0.793895081677709, 1.09376525878906, (0.459143716617349, 0.888362002502813))
],
[	Point(2, (426.5625, 640.083251953125), (426.5625, 640.083251953125), 0.25, 0.0, 0.0, 0.333333333333333,4.16666666666667, 0.791362122693334, 1.10859680175781, (0.445917921389058, 0.895073855826469)), 
	Point(2, (426.4375, 639.624633789062), (426.4375, 639.624633789062), 0.25, 0.0, 0.00500000000465661, 0.333333333333333,4.16666666666667, 0.791362122693334, 1.10859680175781, (0.445917921389058, 0.895073855826469)), 
	...
Point(2, (456.8125, 775.628540039062), (456.8125, 775.628540039062), 0.25, 0.0, 0.525000000001455, 0.115626017252604,4.16666666666667, 0.849620179333959, 1.10678100585938, (0.447542456811074, 0.894262684758515))
]]	 
```

全コードはこちらになります。

https://gist.github.com/codelynx/9147adc6ad4eaac89ca66c8ad2b24036

<img width="160" src="https://qiita-image-store.s3.amazonaws.com/0/65634/79dc5b3d-fe61-8115-cfe9-558453110edf.png" />

## 使い方

Touch Coder をビルド＆実行させると、白い画面が現れるので、そこを指や Apple Pencil で文字を書いたり、絵を描いたりと好きに描きます。間違えたり気に入らない場合は、Trash ボタンでクリアする事ができます。

そして、気に入った文字や絵が仕上がった時には、アクティビティアイコンをタップするとシェアなどをする方法が選べます。

お好きな方法で Xcode までコードを持ってきて、目的に応じて、コードに手を入れて目的達成です。

# あとがき

こうして色々な人のペン先のデータが集まると面白いかなとも思いました。

［環境に関する表記］

```.log
Xcode Version 8.2.1 (8C1002)
Target: x86_64-apple-macosx10.9
```