5

このトピックは 1 回か 2 回スクラッチされていますが、私はまだ困惑しています。また、Google も友好的ではありませんでした。

Quartz はアフィン変換を使用して任意の座標系を使用できるため、実際の座標 (足など) を使用して間取り図などを描画できるようにしたいと考えています。

基本的に、例として、10x10 の長方形 (たとえば 10 インチのボックスを考えてください) を描画すると、60x60 ピクセルの長方形が得られるように、ビューをスケーリングします。

私が得る四角形がかなりあいまいであることを除いて、それは機能します。ここで別の質問をすると、その理由を説明する回答が得られました。しかし、私はその理由を理解しているかどうか確信が持てず、さらにそれを修正する方法も知りません。これが私のコードです:

awakeFromNibカスタム ビュー メソッドで座標系を設定します。

- (void) awakeFromNib {
    CGAffineTransform scale = CGAffineTransformMakeScale(6.0, 6.0);
    self.transform = scale;
}

そして、これが私のドロールーチンです:

- (void)drawRect:(CGRect)rect {
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGRect r = CGRectMake(10., 10., 10., 10.);
    CGFloat lineWidth = 1.0;
    CGContextStrokeRectWithWidth(context, r, lineWidth);
}

私が得た正方形はうまくスケーリングされていますが、完全にぼやけています。で遊んでlineWidthも役に立ちません。 をlineWidth小さく設定すると、軽くなりますが、鮮明にはなりません。

ドメイン座標を使用できるように、スケーリングされた座標系を持つようにビューを設定する方法はありますか? それとも、元に戻って描画ルーチンにスケーリングを実装する必要がありますか?

この問題は、平行移動または回転では発生しないことに注意してください。

ありがとう

4

2 に答える 2

10

私が得た[ストロークされた]長方形はかなりぼやけています。

通常、これは四角形を整数座標にプロットし、線幅が 1 であるためです。

PostScript (およびその子孫である AppKit、PDF、Quartz) では、描画単位のデフォルトはポイントであり、1 ポイントは正確に 1/72 インチです。Mac と iPhone は現在*、画面の実際の解像度に関係なく、そのようなすべてのポイントを 1 ピクセルとして扱います。そのため、実用的な意味では、ポイント (デフォルトでは Mac と iPhone では) はピクセルに等しくなります。

PostScript とその子孫では、整数座標がポイント間を走ります。たとえば、0、0 は左下点の左下隅です。1、0 は同じポイントの右下隅 (および右隣のポイントの左下隅) です。

ストロークは、ストロークしているパスの中心に配置されます。したがって、半分はパスの内側、半分は外側になります。

Mac の (概念的に) 72 dpi の世界では、これら 2 つの事実が組み合わさって問題が生じます。1 ポイントが 1 ピクセルに等しい場合、2 つのピクセル間に 1 ポイントのストロークを適用すると、ストロークの半分がそれらの各ピクセルに当たります。

少なくとも Quartz は、現在の色を色のアルファの半分で両方のピクセルにペイントすることでこれをレンダリングします。これは、概念的なストロークでカバーされるピクセルの量によって決まります。1.5 pt の線幅を使用した場合、その半分は 0.75 pt であり、これは各 1 pt ピクセルの 4 分の 3 であるため、色は 0.75 アルファでレンダリングされます。もちろん、これは自然な結論になります。2 ポイントの線幅を使用すると、各ピクセルが完全に覆われるため、アルファは 1 になります。 2ポイントストローク。

いくつかの回避策があります。

  • ハーフポイントの翻訳: ボックスに記載されているとおり、前述の 1 ポイント カット イン ハーフ ディビジョンを補うために、上と右に 0.5 ポイントだけ翻訳します。

    これは単純なケースでは機能しますが、全点変換以外の他の座標変換が関係する場合は剥がれ落ちます。つまり、30、20 で平行移動しても機能しますが、33+1/3、25.252525 で平行移動すると、またはスケーリングまたは回転がまったく行われない場合、半点の平行移動は役に立たなくなります。 .

  • 内側のストローク: 最初にクリップし、次に線幅を 2 ​​倍にして (半分しか描画しないため)、次にストロークします。

    クリッピングパスが他の描画に影響を与えたくないため、他に多くの描画を行う場合は、gstate ジャグリングが必要になる場合があります。

  • 外側のストローク: 基本的に内側のストロークと同じですが、クリッピングの前にパスを逆にする点が異なります。

    ストロークしたいパスが重ならないことが確実な場合は、内側のストロークよりも優れています (gstate のジャグリングが少ない)。一方、パスも埋めたい場合は、gstate ジャグリングが返されます。

※いつまでも続くわけではありません。Apple はしばらく前から、少なくとも Mac の描画解像度をいつか変更するというヒントを出していました。このような変更のための API 基盤は、ほぼすべて揃っています。それはすべて、Apple がスイッチを入れるかどうかの問題です。

于 2010-03-21T21:30:26.650 に答える
2

まあ、よくあることですが、問題を説明することで解決策が見つかります。

問題は、ビュー変換プロパティがビットバッファに描画された後に適用されることです。スケーリング変換は、描画する前に適用する必要があります。drawRectメソッドで。だから私が与えたスクラッチawakeFromNib、そしてここに正しいdrawRectがあります:

- (void)drawRect:(CGRect)rect {
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGAffineTransform scale = CGAffineTransformMakeScale(6.0, 6.0);
    CGContextConcatCTM(context, scale);
    CGRect r = CGRectMake(10., 10., 10., 10.);
    CGFloat lineWidth = 0.1;
    CGContextStrokeRectWithWidth(context, r, lineWidth);
}
于 2010-03-21T18:23:27.640 に答える