Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
Help us understand the problem. What is going on with this article?

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

More than 5 years have passed since last update.

タッチされた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 などのプロパティを追加してみました。

koher
Swift は他の多くの言語と異なり値型中心の言語です。そんな Swift を学ぶ上で重要なポイントをまとめたオンライン書籍 "Heart of Swift" ( https://heart-of-swift.github.io ) を書きました。
https://heart-of-swift.github.io
qoncept
リアルタイム画像認識を専門にした会社です。近年はスポーツにおける認識技術の応用に力を入れています。
https://qoncept.co.jp/
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