ハンサムスーツ観ますた。

 今までのCTMやベジェ曲線描画実験を応用して、チンパンジーゲーム用のビューに独自のレベル設定用ビュー描画を組み込むわけだけど、本体への移植をやりやすくするために、機能をまとめたクラスとして定義してみる。

@interface LevelMeter : NSObject {
double radius;
double angle;
CGPoint center;
}
- (void)set:(CGPoint)inPos r:(int)inRadius angle:(double)inRadian;
- (double)pointToNumber:(CGPoint)inPos;
- (void)draw:(CGContextRef)inContext num:(double)inNumber;
@end


こんな感じ。

- (void)set:(CGPoint)inPos r:(int)inRadius angle:(double)inRadian;

LevelMeterの画面上の中心、半径、角度を指定する。

テン・シー・シー-fig.1

- (double)pointToNumber:(CGPoint)inPos;

 受け取った座標inPosからLevelMeterが描く扇の円弧上のどの位置か0.0~1.0の値で返す。

テン・シー・シー-fig.2


-(void)draw:()inContext num:(double)inNumber

 inContext上にLevelMeterを描画する。この時、矢印の向きを0.0~1.0の範囲でinNumberによって指定。

pointToNumberでの計算

 中心点と受け取ったinPos点で指定されるベクトルを単位ベクトルにしたさいのx,y成分はそれぞれ、consΘ、sinΘとなる。

テン・シー・シー-fig.3

 そのため、今回ならacosによってΘを求めることができる(asinでは変化する範囲がLevelMeterの扇の範囲をカバーできない)。

テン・シー・シー-fig.4

 もちろんasinの変化はacosが上側のエリアでの変化なのか、下側のエリアなのかの判断には使える。

テン・シー・シー-fig.5

 が、今回はもっと簡単に中心点よりy座標が大きければ、下側のエリアと判断し、x座標で0.0か1.0にしてしまう。
 受け取ったinPos点と中心点が一致した場合は、計算不可能。今回は0.0を返すことにする。

テン・シー・シー-fig.6

 ま、こんな感じでLevelMeter実装の準備ができたので、あとは「iPhoneアプリ開発、その(60)」「その(40)」を参考に実際の実装をおこない、helloCTMView.mで利用する。
 例のごとくinitWithFrameは呼ばれないので、setupLevelMeterってのを用意しました。

- (void)setupLevelMeter {
meter = [[[LevelMeter alloc] init] retain];
[meter set:CGPointMake(self.frame.size.width / 2, self.frame.size.height / 2) r:100.0 angle:0.0];
}

 解放の方はdeallocでばっちり対応可能。

- (void)dealloc {
[super dealloc];
[meter release];
}

 drawRectでLevelMeterインスタンスを使って描画するのと、「iPhoneアプリ開発、その(63)」を参考にtouchesBegan、touchesMovedを実装しLevelMeter インスタンスのpointToNumberを呼び出す。

 今回は、まだ上のエリアか、下のエリアかとか、扇の角度とかぜんぜん対応してません。
 とりあえず、画面触ると前回の矢印がグルグル動くので、腕に自信のある人は、こいつを参考に前の前の数字表示まで実装しちゃってください。

テン・シー・シー-fig.7

 あと、drawメソッドの中で使われてる

CGContextConvertPointToDeviceSpace

は、今回お初です。これがどういう役割を果たしているかはその次の行

CGContextTranslateCTM

を削ってみるとわかるよん。
 詳細は次回!

------------
サンプルプロジェクト:helloCTM-7.zip