C4入門

#はじめに

Swift Advent Calendar 2016 １４日目です。

`Swift Advent Calendar 2016`ということで、Swiftに関する話を書こうと思っていたのですが拡大解釈してC4入門の記事を書きます。お許し下さいッ…！！

#C4とは

http://www.c4ios.com/

簡単に言えばCoreGraphicsやCoreAnimationを扱いやすくしたものだとか、OpenFrameworkのCoreGraphics版とかそういったものです。
描画系関数や数値計算・生成系関数のセットがSwift3.0で書かれています。

極めればOpenFrameworkのように「Swift出来ればVJ出来ちゃう」みたいな感じのイケイケヒップホップエンジニアになれるはずです。

オシャレな展示を作るのに使ってもよし、UX向上の為に使ってもよしです。
しかも記述も非常に簡単なのでこれからSwiftを始める人にもおすすめです。

#インストール方法

```ruby:Podfile
target 'C4Lab' do
  use_frameworks!
  pod 'C4'
end
```

cocoapodsに対応しているので、Podfileに書けばインストール出来ます。
公式サイトにはCarthageやマニュアルインストールの方法も書いてあるので、好みによって参照してください。

#標準の描画関数

関数の殆どはC4独自のものですが、基本的にはUIKitやFoundationからプリフィクスを取った(Point/Rect/Transformなど)が使われます。
またそれぞれにFoundationの構造体を引数に取って生成するイニシャライザがあるので、例えばCGRectをRectに変換する場合も`Rect(cgrectValue)`のように、書くことができます。
これはSwiftのキャストと非常に記述が似ているので自然に使う事ができます。

以下は[公式チュートリアル](http://www.c4ios.com/tutorials/basics/)の基本的な部分を抜粋しています。

##背景を青で塗る

```swift:ViewController.swift
final class ViewController: CanvasController {
  override func setup() {
    canvas.backgroundColor = C4Blue
  }
}
```

基本的にC4ではUIViewControllerの代わりにCanvasControllerを継承します。
CanvasControllerにはUIViewControllerにviewが生えているようにcanvasが生えており、それに対してC4のViewをaddして行きます。

![スクリーンショット 2016-12-12 23.20.06.png](https://qiita-image-store.s3.amazonaws.com/0/24979/1fe56cd4-e74d-4811-3159-a1668ceba464.png)

上記はcanvasの背景色を青にした状態です。
viewDidLoadに初期化の記述を書くように、C4ではsetup関数の中に初期化のプロセスを記述します。

##四角を描く

```
final class ViewController: CanvasController {
  override func setup() {
    let square = Rectangle(frame: Rect(0, 0, 100, 100))
    square.center = canvas.center
    canvas.add(square)
  }
}
```

![スクリーンショット 2016-12-12 23.35.51.png](https://qiita-image-store.s3.amazonaws.com/0/24979/a7585da6-ebac-2b8c-b7b2-8935f4aab881.png)

ビューの追加はUIViewをaddSubViewする時と同じように行います。
addメソッドの内部では

```swift:View.swift
    public func add<T>(_ subview: T?) {
        if let v = subview as? UIView {
            view.addSubview(v)
        } else if let v = subview as? View {
            view.addSubview(v.view)
        } else {
            fatalError("Can't add subview of class `\(type(of: subview))`")
        }
    }
```

このような分岐が行われており、C4のViewの場合はC4.ViewからUIViewを生成してaddSubViewをしています。

C4では一定のパターンの図形はクラスとして定義されており、簡単に生成することが出来ます。

##円を描く

```
final class ViewController: CanvasController {
  override func setup() {
    let circle = Circle(center: canvas.center, radius: 50)
    canvas.add(circle)
  }
}
```

![スクリーンショット 2016-12-12 23.37.00.png](https://qiita-image-store.s3.amazonaws.com/0/24979/ac50d3b7-a8fe-897a-79a6-df1982a1daeb.png)

円を描く際、自前で行うとボーダーラインがframeから漏れてしまい微妙に小さくしたりする事がありますがC4では内側に線を引いてくれるようです。

##楕円を描く


```
final class ViewController: CanvasController {
  override func setup() {
    let ellipse = Ellipse(frame: Rect(0, 0, 200, 100))
    ellipse.center = canvas.center
    canvas.add(ellipse)
  }
}
```

![スクリーンショット 2016-12-12 23.37.47.png](https://qiita-image-store.s3.amazonaws.com/0/24979/5e0d4b61-9808-fed8-a493-a85b093f83ba.png)

CircleはEllipseを継承しており、継承元のEllipseではCircleで補正されているアス比を無視して楕円を描画することが出来ます。

##線を描く

```
final class ViewController: CanvasController {
  override func setup() {
    let points = (Point(), Point(100, 100))
    let line = Line(points)
    line.center = canvas.center
    canvas.add(line)
  }
}
```

![スクリーンショット 2016-12-12 23.38.42.png](https://qiita-image-store.s3.amazonaws.com/0/24979/9280d6f2-1322-4304-a527-6a6f07457131.png)

基本的な線を描画します。

##三角を描く

```
final class ViewController: CanvasController {
  override func setup() {
    let points = [Point(), Point(100, 100), Point(200, 0)]
    let triangle = Triangle(points)
    triangle.center = canvas.center
    canvas.add(triangle)
  }
}
```


![スクリーンショット 2016-12-12 23.39.24.png](https://qiita-image-store.s3.amazonaws.com/0/24979/a007f1c1-9c3a-d6cf-7232-b2282fcf6586.png)

Triangleクラスは与えるpointsが３つ以下だとassertしてくれます。

##ポリゴンを描く


```
final class ViewController: CanvasController {
  override func setup() {
    let points = [Point(), Point(100, 100), Point(200, 0), Point(300, 100)]
    let polygon = Polygon(points)
    polygon.center = canvas.center
    canvas.add(polygon)
  }
}

```

![スクリーンショット 2016-12-12 23.40.11.png](https://qiita-image-store.s3.amazonaws.com/0/24979/1e30172c-82e9-53a8-b43b-9e969c9383e3.png)

PolygonはTriangleやLineの基底クラスです。
基本的にはPolygonを使えばTriangleやLineと同じように描画出来ます。

##多角形

```
final class ViewController: CanvasController {
  override func setup() {
    let regularPolyon = RegularPolygon(center: canvas.center, radius: 50.0, sides: 6, phase: 0.0)
    canvas.add(regularPolyon)
  }
}
```

![スクリーンショット 2016-12-12 23.41.58.png](https://qiita-image-store.s3.amazonaws.com/0/24979/05c489bb-e7ca-ce70-d30c-110fef2ef053.png)

多角形を描画します。これも基底クラスはPolygonです。

##星を描く

```
final class ViewController: CanvasController {
  override func setup() {
    let star = Star(center: canvas.center, pointCount: 5, innerRadius: 25.0, outerRadius: 50.0)
    canvas.add(star)
  }
}
```

![スクリーンショット 2016-12-12 23.42.31.png](https://qiita-image-store.s3.amazonaws.com/0/24979/919268ac-ce98-1959-633b-a7e6381a7c5f.png)

Starという名前がついていますが、頂点を凸部分は５つ以上にすることで破裂型吹き出しのような形にすることも出来ます。

ここまではSketchにあるシェイプによく似ていますね

<img width="158" alt="スクリーンショット 2016-12-13 1.53.37.png" src="https://qiita-image-store.s3.amazonaws.com/0/24979/398a93df-52a7-acdf-45c5-d3b1d9e52ab9.png">


##かまぼこ型を描く

```
final class ViewController: CanvasController {
  override func setup() {
    let arc = Arc(center: canvas.center, radius: 50, start: M_PI, end: 2 * M_PI)
    canvas.add(arc)
  }
}
```

![スクリーンショット 2016-12-12 23.43.06.png](https://qiita-image-store.s3.amazonaws.com/0/24979/666dece0-5437-a1de-dcdb-914e9733a5ca.png)



##楔形を描く

```
final class ViewController: CanvasController {
  override func setup() {
    let wedge = Wedge(center: canvas.center, radius: 50, start: 1.25 * M_PI, end: 1.75 * M_PI)
    canvas.add(wedge)
  }
}
```

![スクリーンショット 2016-12-12 23.43.46.png](https://qiita-image-store.s3.amazonaws.com/0/24979/7a91a219-ee87-8fb5-01b3-23ea150ea4c5.png)

ピザ型を表現できます。
タイマーの経過のアニメーションにも使えそうですね。


##テキストを描画する

```
final class ViewController: CanvasController {
  override func setup() {
    let string = "C4"
    let textShape = TextShape(text: string)!
    textShape.center = canvas.center
    canvas.add(textShape)
  }
}
```

![スクリーンショット 2016-12-12 23.44.27.png](https://qiita-image-store.s3.amazonaws.com/0/24979/a9b9230c-7264-656e-0337-e1c6b2dbe0b6.png)

テキストを直接描画します。
フォントを選ぶこともできます

```
final class ViewController: CanvasController {
  override func setup() {
    let string = "日本語のテスト"
    let textShape = TextShape(text: string)!
    textShape.center = canvas.center
    canvas.add(textShape)
  }
}
```

![スクリーンショット 2016-12-12 23.44.54.png](https://qiita-image-store.s3.amazonaws.com/0/24979/515f3972-7731-bbb1-e10b-8a41e80ebc85.png)

日本語は表示されないようです。
フォントの問題なのかな

#プロパティ

##基本的なプロパティ

```
final class ViewController: CanvasController {
  override func setup() {
    let r = Rectangle(frame: Rect(0, 0, 100, 100))
    r.center = canvas.center
    r.lineWidth = 8 //線の太さ
    r.strokeColor = C4Blue //線の色
    r.fillColor = C4Pink //塗りの色
    canvas.add(r)
    canvas.backgroundColor = C4Purple //背景色
  }
}
```

![スクリーンショット 2016-12-12 23.50.29.png](https://qiita-image-store.s3.amazonaws.com/0/24979/e7ede29f-9cf4-12eb-4860-5e62295647da.png)

太さや色、塗り色などを指定出来ます。

#色について

##基本色

基本色が存在し、この色はC4をimportしていれば
`backgroundColor = black`
のように直接呼び出す事ができます。

```
black
darkGray
lightGray
white
gray
red
green
blue
cyan
yellow
magenta
orange
purple
brown
clear
C4Pink
C4Blue
C4Purple
C4Grey
```

##カスタムカラー

UIColorやCGColorから生成したりRGBを指定して生成することも出来ます。

```
Color(UIColor.red.cgColor)
Color(UIColor.red)
Color(12)
Color(red: 0.25, green: 0.5, blue: 0.75, alpha: 1.0)
```

##カスタムカラー２

`Color(pattern: String)`を使うと画像を敷き詰める事ができます。
これもC4の世界ではColorとして扱います。

```
final class ViewController: CanvasController {
  override func setup() {
    canvas.backgroundColor = Color("image1")
  }
}
```

![スクリーンショット 2016-12-13 0.00.55.png](https://qiita-image-store.s3.amazonaws.com/0/24979/f55af127-99fe-6e88-566c-fa8114f7312b.png)

#画像

##Image

```
final class ViewController: CanvasController {
  override func setup() {
    let image = Image("image1")!
    image.center = canvas.center
    canvas.add(image)
  }
}
```

![スクリーンショット 2016-12-13 0.02.33.png](https://qiita-image-store.s3.amazonaws.com/0/24979/4fdec724-35bf-ac67-337f-a4f972e288d7.png)

画像も単体のクラスとして存在します。UIImageViewと違い、Image自体をcanvasにadd出来ます。

##Filter


```
final class ViewController: CanvasController {
  override func setup() {
    let image = Image("image1")
    image?.center = canvas.center
    canvas.add(image)
    
    var dotScreen = DotScreen()
    dotScreen.width = 10.0
    image?.apply(dotScreen)
  }
}
```

![スクリーンショット 2016-12-13 0.03.27.png](https://qiita-image-store.s3.amazonaws.com/0/24979/f2d1ed7c-58d2-86de-cbda-4ae8ba030ca9.png)

フィルタをかける処理も短く書けます。
C4にはDotScreen以外にもガウジアンブラーやブルームといったフィルターも最初から入っています。
もちろんFilterクラスを継承すれば自分でフィルタを作ることも出来ます。
フィルタの実態はCIFilterなので、CIFilterが書ける人はもちろんOpenGLのシェーダーを使うことも出来ます。

##Generate Image

```
final class ViewController: CanvasController {
  override func setup() {
    let image = Image()
    image.frame = Rect(0, 0, 100, 100)
    
    let checkerBoard = Checkerboard()
    image.generate(checkerBoard)
    image.center = canvas.center
    canvas.add(image)
  }
}
```

![スクリーンショット 2016-12-13 0.06.39.png](https://qiita-image-store.s3.amazonaws.com/0/24979/bb8ee9c3-f94a-96db-5fd9-d11becd215d3.png)

画像を生成するクラスです。
現在C4にはLinearGradientとCheckerboardしかありません。

#Video

##再生

```
final class ViewController: CanvasController {
  override func setup() {
    let movie = Movie("ipod.mov")
    movie?.center = canvas.center
    canvas.add(movie)
    movie?.play()
  }
}
```

![C4.gif](https://qiita-image-store.s3.amazonaws.com/0/24979/0e57eceb-96b1-5699-2fdd-ab070f005349.gif)

AVFoundationを意識せずに再生できます。
このMovie自体にもフィルタをかけたり出来ます。
上記のgifのようにデフォルトでは自動的にリサイズはされず、実サイズで再生されます。

#Gesture

C4ではUIGestureRecognizerもラップした関数があり、Viewに生えています。
直感的にビューに対してタップやパンの時の処理を書くことが出来ます。

##タップ

```
final class ViewController: CanvasController {
  override func setup() {
    let square = Rectangle(frame: Rect(0, 0, 100, 100))
    square.addTapGestureRecognizer { (locations, center, state) in
      square.fillColor = red
    }
    canvas.add(square)
  }
}
```

#アニメーション

C4ではアニメーションはViewAnimationクラスを使って記述します。
ViewAnimationクラスは繋げたり同時に実行したりループしたりが簡単に行えて、色や移動の補完も自動的に行ってくれます。

##基本的なアニメーション

```
ViewAnimation(duration: 1.0) {
        square.fillColor = C4Pink
}.animate()
```

このようにduraitonを指定しクロージャ内で最終状態を記述します。
UIView.animateWithDurationと非常に似ています。

```
let anim = ViewAnimation(duration: 1.0) {
    self.canvas.backgroundColor = C4Blue
}

anim.curve = .EaseOut
anim.repeats = true

wait(1.0) {
    anim.animate()
}
```

ViewAnimation自体はインスタンスを返すので、それに対してプロパティを付与することでアニメーションを変化させることが出来ます。

#色々遊んでみた

##四角と円形をタップで切り替える

```
final class ViewController: CanvasController {
  
  private var isCircle = false
  
  override func setup() {
    let square = Rectangle(frame: Rect(0, 0, 100, 100))
    square.corner = Size(10, 10)
    square.center = canvas.center
    canvas.add(square)
    
    _ = square.addTapGestureRecognizer { (locations, center, state) in
      self.isCircle = !self.isCircle
      if self.isCircle {
        ViewAnimation(duration: 1.0, animations: {
          square.corner = Size(10, 10)
        }).animate()
      } else {
        ViewAnimation(duration: 1.0, animations: {
          square.corner = Size(50, 50)
        }).animate()
      }
    }
  }
}
```

![circle.gif](https://qiita-image-store.s3.amazonaws.com/0/24979/442e9542-ab22-b697-37da-7d1eff123055.gif)


##C4.ViewをUIViewのように追加する

C4.CanvasControllerじゃなくてもいいっぽい

```
final class ViewController: UIViewController {
  override func viewDidLoad() {
    super.viewDidLoad()
    let rect = Rect(CGRect(x: 0, y: 0, width: 100, height: 100))
    let c4v = C4.View(frame: rect)
    c4v.center = Point(view.center)
    c4v.backgroundColor = red
    view.add(c4v)
  }
}
```

![Simulator Screen Shot 2016.12.13 0.53.34.png](https://qiita-image-store.s3.amazonaws.com/0/24979/2e39da51-e579-1356-f176-259e79403dec.png)

##モーフィング

```
final class ViewController: CanvasController {
  override func setup() {
    let c1 = Circle(center: canvas.center, radius: 20)
    c1.fillColor = clear
    c1.strokeColor = lightGray
    canvas.add(c1)
    
    let c2 = Circle(center: canvas.center, radius: 20)
    c2.fillColor = clear
    c2.strokeColor = lightGray
    canvas.add(c2)
    
    let c3 = Circle(center: canvas.center, radius: 20)
    c3.fillColor = clear
    c3.strokeColor = lightGray
    canvas.add(c3)
    
    let c1Anim = ViewAnimation(duration: 1.0, animations: {
      c1.transform = Transform.makeScale(0.2, 0.2)
    })
    
    let c2Anim = ViewAnimation(duration: 1.0, animations: {
      c2.transform.scale(0.2, 0.2)
      c2.transform.translate(Vector(x: -50, y: 0))
    })
    
    let c3Anim = ViewAnimation(duration: 1.0, animations: {
      c3.transform.scale(0.2, 0.2)
      c3.transform.translate(Vector(x:  50, y: 0))
    })
    
    canvas.addTapGestureRecognizer { (_, _, _) in
      ViewAnimationGroup(animations: [c1Anim, c2Anim, c3Anim]).animate()
    }
  }
}
```

![mop.gif](https://qiita-image-store.s3.amazonaws.com/0/24979/21d5bd2a-e7dd-14aa-fc5a-0e9d9286d7d0.gif)


#まとめ
基本的なところをさらっと載せました。
C4はCoreGraphicsやUIKitを使っていることもあり、低コストにマイクロインタラクションを実装したり出来るなど、一般的なアプリケーション開発との親和性も高そうに思えました。

エンジニアがちょっとした動きを実装したり、デザイナーも実際にコードを触って実装に関われるような簡単さもあって中々楽しいのではないでしょうか。

このC4を通してSwiftを知ったり、逆にエンジニアが芸術・展示作品に対してコミットしていくという事が出来そうに思います。

明日は @_ha1f さんの 「Photos.frameworkのサンプルリーディング」です！
それでは！