Cocoa環境で幅1pxの一本の線を描くために
Cocoa環境で一本の水平ラインを描こうと考えて、最初に思い付いたのはベジェ曲線NSBezierPathを利用する方法だった。しかし、ベジェ曲線NSBezierPathの特性をちゃんと理解できていないため、幅1pxの線を引くことに苦労してしまった。以下は一本の線を引く過程で自分が理解したことのメモ。
setDefaultLineWidth:1を指定しても2pxの線が描画される場合がある
- (void)drawRect:(NSRect)rect { NSRect testRect = NSMakeRect(50,50,100,100); [[NSColor greenColor] set]; [NSBezierPath setDefaultLineWidth:1]; [NSBezierPath strokeLineFromPoint:NSMakePoint(50,120) toPoint:NSMakePoint(150,120)]; [NSBezierPath setDefaultLineWidth:2]; [NSBezierPath strokeLineFromPoint:NSMakePoint(50,100) toPoint:NSMakePoint(150,100)]; [[NSColor brownColor] set]; NSFrameRect(testRect); }
NSViewのサブクラスを定義して、drawRectメソッドに上記コードを書いて実行してみると、以下のような結果になる。
- setDefaultLineWidth:1とsetDefaultLineWidth:2が同じ2pxの幅になっている。(周囲の茶色の枠線が幅1px)
- setDefaultLineWidth:1よりsetDefaultLineWidth:2の色が若干濃い。(ちょっと分かり難いかもしれないが)
ベジェ曲線NSBezierPathとNSFrameRectの違い
ライン幅20の四角形をそれぞれの方法で描いてみた。
ベジェ曲線NSBezierPathで描画
- (void)drawRect:(NSRect)rect { NSRect testRect = NSMakeRect(50,50,100,100); [[NSColor whiteColor] set]; [NSBezierPath setDefaultLineWidth:20]; [NSBezierPath strokeRect:testRect]; [[NSColor brownColor] set]; NSFrameRect(testRect); }
NSFrameRectで描画
- (void)drawRect:(NSRect)rect { NSRect testRect = NSMakeRect(50,50,100,100); [[NSColor whiteColor] set]; NSFrameRectWithWidth(testRect, 20); [[NSColor brownColor] set]; NSFrameRect(testRect); }
- ベジェ曲線NSBezierPathは、指定した四角形のラインを中心に、両側に指定した幅の1/2(10px)ずつの領域を確保して、20px幅の四角形を描画している。
- 一方、NSFrameRectは、指定した四角形の範囲に収まるような20px幅の四角形を描画している。
ベジェ曲線NSBezierPathが描画するときの気持ち
以上のことから考えて、1pxの水平ラインをNSBezierPathで描画しようとすると、以下のような現象が発生していると考えられる。
- 非常に単純な以下のスクリーンを想像して...
(y軸) 2┌┬┬┬┐ 1├┼┼┼┤ 0└┴┴┴┘ 0 1 2 3 4(x軸)
- 幅1pxのベジェ曲線で直線を描こうとすると...
[NSBezierPath setDefaultLineWidth:1]; [NSBezierPath strokeLineFromPoint:NSMakePoint(0,1) toPoint:NSMakePoint(4,1)];
幅1pxの線を描く方法
- NSFrameRectを使う。
- NSBezierPathを利用する場合は、中心となる線を0.5pxずらして指定する。
- (void)drawRect:(NSRect)rect { NSRect testRect = NSMakeRect(50,50,100,100); [[NSColor greenColor] set]; NSFrameRect(NSMakeRect(50,120,100,1)); [NSBezierPath setDefaultLineWidth:1]; [NSBezierPath strokeLineFromPoint:NSMakePoint(50,100.5) toPoint:NSMakePoint(150,100.5)]; [[NSColor brownColor] set]; NSFrameRect(testRect); }
一本の線を引くのも奥が深い...。思い返せば、初めての書道で書いたのも漢数字の「一」だったような気がする。(筆の入りと止めを理解する第一歩)最もシンプルな一本の水平ラインの描き方を理解することはとても重要なのであった。