今回は座標系変換について。
flippedから non-flippedへ
SimpleCap のメインとなるビューの CaptureView は、NSViewのサブクラスなので通常は座標系は左下原点だが、フリップ(flipped)させているので左上原点となっている。
一方、Core Animation(CALayer)の座標系は左下が原点となっている。
この為、CaptureView の座標を使って CALayer へ描画する際は flippedな座標系から、non-flippedな座標系への変換が必要になる。
変換
ここでは矩形(NSRect or CGRect)を変換対象と考えてみる。NSRect flippedRect から nonFlippedRect へ変換する場合、スクリーンが1つの場合は簡単でこんな感じで求められる。
NSRect screenFrame = [[NSScreen mainScreen] frame]; nonFlippedRect = flippedRect; nonFlippedRect.origin.y = screenFrame.size.height - flippedRect.origin.y - flippedRect.size.height;
やっかいなのはマルチスクリーンの場合。上記コードのmainScreen以外も考慮に入れる必要がある。
以前調査したようにスクリーンの配置の仕方によって各スクリーンが置かれる座標が異なる。
[参考情報] (旧) Cocoaの日々: β版バグ修正 - マルチスクリーン
今回は下記のケースはこの時の「b. SimpleCapのメインビューのローカル座標系」から「a. スクリーン座標系」への変換に該当する。
まず X座標については変換は不要。flippedの有無は Y座標のみ関係していて、それを除けば基本的に同じ座標系だから。
Y座標についてはサブ画面の位置によって次の2つのケースを考える。
[a] サブ画面が上に載るケース
[b] サブ画面が下に載るケース
変換の考え方は原点を中心に考えるとわかりやすい。
[参考情報] (旧) Cocoaの日々: β版バグ修正 - マルチスクリーン(その2)
そのアプローチで考えた数式は次の通り。
cx1 = lx1; cy1 = sy2 - ly1 - lh1;・スクリーン座標系上での全画面範囲(左下)-(右上):(sx1, sy1)-(sx2, sy2)
・fliipedな座標系内の NSRect:(lx1, ly1),(lw1, lh1)
・(non-flippedな)変換後の座標:(cx1,cy1)
スクリーン1つの場合と似ているが、その時のスクリーンの高さを起点にしていたのに対してマルチスクリーンの場合はそこにスクリーン全体の座標で補正している点。
確認
シングルスクリーンでは問題なし。マルチスクリーンは手元に無いため未確認...。