SSブログ

Mac用プロットライブラリ-10 [考え中 - プロットライブラリ]

しばらく進んでなかった設計の続き。結構難しい問題が発覚した。
描画オブジェクトには上位レイヤでもNormalized座標やView座標の座標値を含むことができるようにしたい。そうすることでテキストオブジェクトのサイズ指定や座標軸のtickの長さなんかの、描画領域の大きさによらない指定が望ましいオブジェクトを作成しやすくする。

ただし、View座標の場合、もとのプロットデータと無関係(どこに描画するかは描画先のNSViewの大きさだけで決まる)なので単独では無意味で、View座標はプロット座標からの相対指定された場合のみ意味がある。例えばテキストオブジェクトのフォントサイズをView座標で指定する意味はあるが描画位置をViewで指定できても無意味で(プロットがどこに描かれるかわからないのにテキストの位置を直接指定できてもしょうがない)、プロットデータの、例えばあるポイントの値を示すなどプロット座標での指定が含まれている必要がある。また、例えばx-座標軸のtickのy方向の長さはView座標で指定できるのが望ましいが、その位置はプロット座標で指定されなければならない。

従って描画オブジェクトに含まれたView座標値はプロット座標からの相対値として表現できる必要がある。例えば具体的なコードとして
@interface CPViewPosition : CPPosition {
	float		x;
	float		y;
	CPPlotPosition	*relativeTo;
}
...
@end
みたいに。これは相対位置指定したView座標で、relativeToはCPViewPositionが保持している(x,y)がどこから測られるかを示すプロット座標となる。ようするにプロット内のrelativeToで指定された位置からView座標(ウィンドウ上の距離で)で指定された距離だけ離れた位置を指定している。当然APIとしてのシンプルさのためには、3種類の座標(Plot、normalized、View)すべてで相対指定できるようにしなければいけない。

さて、 こうすることでPlot座標に相対的なViewでの位置が指定できることになるけど、実装上の問題が発生する。それはPlot座標からNormalized座標に変換するときにBoundingBoxの大きさがPlot座標で表現できなくなることである。例を図-4に示す。
0329fig4.png
これはPlot座標で描かれた領域の右上端の位置(px,py)を起点にする相対View座標指定(vx,vy)がさらに右上に出る場合。Plot領域をNormalized座標に変換する場合にはこれらを含むBoundingBoxの大きさが必要となるけど、この相対View座標で指定された位置(vx,vy)はViewの大きさが確定するまで(Plot座標がView座標に変換されるまで)確定せず、結局BoundingBoxの計算を解決できない。こういうことは座標軸を描いたり、Plot Labelを書いたりする場合に頻繁に起こることになる。

この問題を解決するためにどうすればいいか、悩んだ。結局こうすることにした。
  1. Plot座標のBoundingBox計算はView座標指定を無視して行う
  2. View座標指定を埋め込んだままPlot座標をNormalized座標に変換する
  3. Normalized座標からView座標に変換するとき、
    1. 相対指定されたView座標をチェックし
    2. それをView領域内に描画できるようなNormalized→View変換を確定
    3. すべてのNormalized→View変換の値域の共通集合への変換を確定
    を最終的なNormalized→View変換とする
こうすることで座標軸やPlot LabelなどView領域の大きさによってそれ自身の大きさが変化しないPlot Ojbectを、一般のPlot Objectと同列に扱うことができるようになるけど、BoundingBoxの外に出る相対View座標位置指定が現れるたびにNormalized→View変換のマトリクスを作らなければならない。

この方法だとそこそこ最適化された、Normalized→View変換が作れるけど
  1. Plot領域の左右の両方、あるいは上下の両方に相対View座標指定されたOjbectがはみ出る場合、描画領域いっぱいに描かれず余白が出る
  2. 実際の描画領域が取れない場合が起こりえる
  3. Mathematicaの描画結果と大きく異なる
となってしまう。一つ目は上述のようなView領域の共通集合を最終的な描画領域としたための問題である。これは一旦Normalized→View変換を決めたあと、上の手順をもう何度か繰り返せば最終的に収束する。けど、それはやりたくないなあ。

二つ目は共通集合が無くなってしまうような場合、例えばx方向の大きさがView座標で100pt指定された二つの長方形がx軸方向にPlot座標で1.0離れて配置されているときに、View領域のx方向の大きさが200pt以下の場合などである。このような場合は、上の手順では破綻してしまって何も描かれないということになってしまうけど、もともとはみ出さずに描画することは不可能なので、どこかの時点でこれを検知してプロットオブジェクトだけでも描かないとまずい。

それから三つ目は、MathematicaではScaled[]とOffset[]がNormalized座標とView座標に対応するが、これらの座標で指定された点がPlot領域の外に出た場合はMathematicaでは描画されない。例えば長い文字列を左端に描いた場合、左半分は外にはみ出て描画されない(Textのデフォルトのアラインはセンタリング)。ただし、Mathematicaでは座標軸は特別扱いされており、座標軸を含めた余白がはじめから用意されている。本当の実装はわからないけどおそらく、座標軸やPlot Labelが要求する領域を先に確保し、それを描画して狭くなった残りの領域を最終的なView座標領域としているんだと思う。このMathematicaの割り切りは簡単だけど、座標軸を他のPlot Objectと区別する必要があり、実装が面倒になる。上の手順では長い文字列はMathematicaと異なり、すべてが表示されるようにNormalized領域が調整される。

とりあえず、これで行こう。でも、座標軸を区別した方がやっぱり簡単かなあ。また悩んでしまうがな。
nice!(0)  コメント(0)  トラックバック(0) 

nice! 0

コメント 0

コメントを書く

お名前:
URL:
コメント:
画像認証:
下の画像に表示されている文字を入力してください。

トラックバック 0

子供たちよ献立03/30 ブログトップ

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。