43
Help us understand the problem. What are the problem?

More than 5 years have passed since last update.

posted at

Organization

Swiftで+や-を使ってCGPointを計算する

タッチされた2点間の距離や方向ベクトルを計算するとき、 CGPoint をベクトルとみなして次のようにできると便利です。

let a = CGPoint(x: 1, y: 2), b = CGPoint(x: -3, y: 5)

let sum = a + b // aとbの和
let distance = (b - a).length // a、b間の距離
let direction = (b - a).unit // a→bの方向ベクトル

Swiftでは struct (構造体)に演算子を定義したり、 extension を使ってプロパティやメソッドを追加することができます。 CGPoint を次のように拡張しておくと便利です。

演算子を定義する

演算子を新たに定義する場合には、次のように、演算子の名前を持った関数を定義します。

func + (left: CGPoint, right: CGPoint) -> CGPoint {
    return CGPoint(x: left.x + right.x, y: left.y + right.y)
}

- の場合でも同じです。

* の場合は、スカラー(この場合は CGFloat )を右からかける場合と左からがあるのでオーバーロードします。

func * (left: CGPoint, right: CGFloat) -> CGPoint {
    return CGPoint(x: left.x * right, y: left.y * right)
}

func * (left: CGFloat, right: CGPoint) -> CGPoint {
    return CGPoint(x: right.x * left, y: right.y * left)
}

内積の計算もオーバーロードして定義します。戻り値の型が CGFloat なことに注意して下さい。

func * (left: CGPoint, right: CGPoint) -> CGFloat {
    return left.x * right.x + left.y * right.y
}

ひき算ではなく、 -a のように - をつけられるようにするには、 prefix キーワードを用いて演算子を定義します。

prefix func - (value: CGPoint) -> CGPoint {
    return CGPoint(x: -value.x, y: -value.y)
}

プロパティを追加する

extension を使えば、 struct に Conputational Property を追加することができます。

次のようにして、 CGPoint (をベクトルとみなした場合)の長さを得るプロパティを追加します。

extension CGPoint {
    var length: CGFloat {
        get {
            return sqrt(self.x * self.x + self.y * self.y)
        }
    }
}

単位ベクトルを得るプロパティも定義しておくと便利です。

extension CGPoint {
    var unit: CGPoint {
        get {
            return self * (1.0 / self.length)
        }
    }
}

メソッドを追加する

プロパティだけでなく、メソッドを追加することもできます。

ベクトルのなす角を計算するメソッドを追加してみましょう。ベクトルのなす角については

\cos \theta = \frac{\bf{a} \cdot \bf{b}}{|\bf{a}| |\bf{b}|}

が成り立つので、次のようにメソッドを定義します。

extension CGPoint {
    func angleFrom(point: CGPoint) -> CGFloat {
        return acos(fmin(fmax(self * point / (self.length * point.length), -1.0), 1.0))
    }
}

fminfmax は、浮動小数点数の計算誤差で 1.0-1.0 をわずかに超えてしまう場合への対処です。

GitHub

せっかくなので、 GitHubに公開しました。 CGPoint+Vector.swift をプロジェクトに追加するだけで使えます。

まとめ

Swiftでは struct に演算子やプロパティ、メソッドを追加することができます。 CGPoint をベクトルとして計算をすることは多いので、 +- の演算子や、 length などのプロパティを追加してみました。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Sign upLogin
43
Help us understand the problem. What are the problem?