タコさんブログ

プログラミングメモと小言

Swift でヒマワリを描く

bitterharvest.hatenablog.com

に触発されて、試しにSwiftで書いてみた。

準備

16進数カラーコードを UIColor に変換する必要があるので、 SwiftでHexColor(#34495eみたいなやつ) - Qiita を参考に、UIColorに簡易イニシャライザを追加する。

extension UIColor {
  convenience init(hexString: String, alpha: CGFloat) {
    let hex = hexString.stringByReplacingOccurrencesOfString("#", withString: "")
    let scanner = NSScanner(string: hex)
    var rgbValue: UInt32 = 0
    if scanner.scanHexInt(&rgbValue) {
      self.init(red: CGFloat((rgbValue & 0xFF0000) >> 16) / 255.0, green: CGFloat((rgbValue & 0xFF00) >> 8) / 255.0, blue: CGFloat(rgbValue & 0xFF) / 255.0, alpha: alpha)
    } else {
      self.init(red: 0.0, green: 0.0, blue: 0.0, alpha: alpha)
    }
  }
  
  convenience init(hexString: String) {
    self.init(hexString: hexString, alpha: 1.0)
  }
}

mkCoords 関数

配置する円の座標を求める関数。

func mkCoords(n: Int) -> [CGPoint] {
  // Helper 関数
  func coord(n: Int) -> CGPoint {
    return fromPolar(sqrt(CGFloat(n)), theta: 2.4 * CGFloat(n))
  }
  
  func fromPolar(r: CGFloat, theta: CGFloat) -> CGPoint {
    return CGPointMake(r * cos(theta), r * sin(theta))
  }

  return (1...n).map(coord)
}

floret 関数

円を作成する関数。とりあえずCALayerにしておく。ここで使用しているカラーセットの定義はここからコピーしてきた。

func floret(r: CGFloat) -> CALayer {
  let layer = CAShapeLayer()
  let path = UIBezierPath(arcCenter: CGPointZero, radius: 0.6, startAngle: 0, endAngle: CGFloat(2 * M_PI), clockwise: true).CGPath
  layer.path = path
  let n = floor(1.4 * sqrt(r)) % 9
  let colors = ["#ffffe5","#fff7bc","#fee391","#fec44f",
    "#fe9929","#ec7014","#cc4c02","#993404",
    "#662506","#000000"].map(UIColor.init).reverse() as [UIColor]
  layer.fillColor = colors[Int(n)].CGColor
  return layer
}

sunflower 関数

ひまわりのレイヤーを返す関数。

func sunflower(n: Int) -> [CALayer] {
  func florets(n: Int) -> [CALayer] {
    return (1...n).map { floret(sqrt(CGFloat($0))) }
  }
  
  return zip(mkCoords(n), florets(n)).map { (position, layer) in
    // 円の位置を変更 
    layer.position = CGPointMake(position.x + 100, position.y + 100)
    return layer
  }
}

SunflowerView クラス

ひまわりを描画するView

class SunflowerView: UIView {
  override func drawRect(rect: CGRect) {
    let baseLayer = CALayer()
    baseLayer.frame = CGRectMake(0, 0, 200, 200)
    sunflower(2000).forEach {
      baseLayer.addSublayer($0)
    }
    // ちょっと拡大
    baseLayer.transform = CATransform3DMakeScale(3.0, 3.0, 0.0)
    layer.addSublayer(baseLayer)
  }
}

完成

SunflowerView(frame: CGRect(x: 0.0, y: 0.0, width: 200.0, height: 200.0))

をaddSubview等すれば完成。以下のようなひまわりが描画される。

f:id:tiny_wing:20160331190347p:plain

注意

試す場合は、Playgroundでは時間がかかるので、Single View Application で行う方が良い(?)

参考URL