2010-03-21 6 views
5

Ce sujet a été rayé une ou deux fois, mais je suis toujours perplexe. Et Google n'était pas sympathique non plus. Puisque Quartz permet des systèmes de coordonnées arbitraires en utilisant des transformations affines, je veux être capable de dessiner des choses comme des plans d'étage en utilisant des coordonnées réelles, par ex. pieds. Par conséquent, à titre d'exemple, je veux redimensionner la vue de sorte que lorsque je dessine un rectangle 10x10 (par exemple une boîte de 10 pouces), j'obtiens un rectangle de 60x60 pixels.Comment configurer un système de coordonnées Quartz2D utilisateur avec mise à l'échelle qui évite le dessin flou?

Cela fonctionne, sauf que le rectangle que je reçois est assez flou. Une autre question ici a obtenu une réponse qui explique pourquoi. Cependant, je ne suis pas sûr d'avoir compris pourquoi, et de plus, je ne sais pas comment y remédier. Voici mon code:

Je mis mon système de coordonnées dans ma méthode vue awakeFromNib personnalisée:

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

Et voici ma routine de tirage:

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

La place que je reçois est mis à l'échelle très bien , mais totalement flou. Jouer avec lineWidth n'aide pas: quand lineWidth est réglé plus petit, il devient plus léger, mais pas plus net.

Y a-t-il un moyen de configurer une vue pour avoir un système de coordonnées mis à l'échelle, afin que je puisse utiliser mes coordonnées de domaine? Ou devrais-je revenir en arrière et implémenter la mise à l'échelle dans mes routines de dessin?

Notez que ce problème ne se produit pas pour la traduction ou la rotation.

Merci

Répondre

2

Eh bien, comme souvent, en expliquant la question me conduire à une solution.

Le problème est que la propriété de transformation de vue lui est appliquée après qu'elle a été dessinée dans un tampon de bits. La transformée d'échelle doit être appliquée avant le dessin, c'est-à-dire. dans la méthode drawRect. Alors gratter la awakeFromNib j'ai donné, et voici un drawRect correct:

- (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); 
} 
+1

Si vous souhaitez définir la largeur de trait en points, quel que soit le facteur d'échelle, définissez-le sur le "nombre de points/facteur d'échelle souhaité". Exemples: La valeur par défaut est 1 pt/1 × = 1; une ligne de 1 pt à votre facteur 6 × est '1,0/6,0'; une ligne de 2 points serait '2.0/6.0'. –

10

le rectangle [caressa] Je reçois est assez floue.

Habituellement, c'est parce que vous avez tracé le rectangle sur les coordonnées de nombre entier et votre largeur de ligne est 1.

Dans PostScript (et donc ses descendants: AppKit, PDF et quartz), unités de dessin par défaut à des points, 1 point étant exactement 1/72 pouces. Le Mac et l'iPhone * traitent actuellement chaque point comme 1 pixel, quelle que soit la résolution réelle de l'écran (s), donc, dans la pratique, les points (par défaut, sur le Mac et l'iPhone) sont égaux aux pixels.

Dans PostScript et ses descendants, les coordonnées intégrales s'exécutent entre les points. 0, 0, par exemple, est le coin inférieur gauche du point inférieur gauche. 1, 0 est le coin inférieur droit de ce même point (et le coin inférieur gauche du point suivant vers la droite).

Un trait est centré sur le tracé que vous dessinez. Ainsi, la moitié sera à l'intérieur du chemin, la moitié à l'extérieur.

Dans le monde (conceptuellement) de 72 dpi du Mac, ces deux faits se combinent pour créer un problème. Si 1 pt est égal à 1 pixel, et que vous appliquez un trait de 1 pt entre deux pixels, alors la moitié du trait atteindra chacun de ces pixels. Le quartz, au moins, rendra cela en peignant la couleur actuelle dans les deux pixels à la moitié de l'alpha de la couleur. Il détermine cela par combien de pixels est couvert par le coup conceptuel; Si vous avez utilisé une largeur de ligne de 1,5 pt, la moitié de celle-ci est de 0,75 pt, soit les trois quarts de chaque pixel de 1 pt, de sorte que la couleur sera rendue à 0,75 alpha. Ceci, bien sûr, va à la conclusion naturelle: Si vous utilisez une largeur de ligne de 2 points, chaque pixel est complètement couvert, donc l'alpha sera 1. Voilà pourquoi vous pouvez voir cet effet avec un coup de 1 pt et non un Coup de 2 pt.

Il existe plusieurs solutions de contournement:

  • Traduction demi-point: Exactement ce qu'il dit sur la boîte, vous traduisez haut et à droite d'un demi-point, compenser ce qui précède 1 pt coupe en - demi-division.

    Cela fonctionne dans des cas simples, mais s'écaille lorsque vous impliquez d'autres transformations de coordonnées, sauf les traductions de points entiers. C'est-à-dire, vous pouvez traduire par 30, 20 et cela fonctionnera toujours, mais si vous traduisez par 33 + 1/3, 25.252525 ..., ou si vous faites une mise à l'échelle ou une rotation, votre traduction en demi-point sera inutile .

  • Coup intérieur: Coupez d'abord, puis doublez la largeur de la ligne (car vous n'en tirerez que la moitié), puis coupez.

    Cela peut nécessiter de jongler avec le gstate si vous avez beaucoup d'autres dessins à faire, car vous ne voulez pas que ce tracé affecte votre autre dessin. Course externe: Essentiellement identique à un trait interne, sauf que vous inversez le chemin avant écrêtage.

    Peut être meilleur (moins de jonglage au gstat) qu'un trait intérieur si vous êtes sûr que les trajectoires que vous voulez contourner ne se chevaucheront pas. D'un autre côté, si vous voulez aussi remplir le chemin, la jonglerie de gstate revient.

* Cela ne durera pas éternellement. Apple laisse tomber des indices depuis un certain temps qu'ils vont changer au moins la résolution de dessin du Mac à un moment donné. La base de l'API pour un tel changement est à peu près tous là maintenant; tout est affaire d'Apple qui lance l'interrupteur.

+0

tout est très vrai, sauf que ce n'est pas la cause du flou que j'ai vécu. Le flou est causé par le fait que le 'UIView.transform' est appliqué à la vue en tant qu'étape post-blitting. Donc ici, il agrandit le bitmap dessiné par 'drawRect'. Simplement en appliquant la transformation * au début * de 'drawRect' le corrige. Cela rend 'UIView.transform' inutile pour la mise à l'échelle. Bien sûr, je vois toujours ce que vous décrivez - le chevauchement des pixels. L'impression visuelle sur les traits verticaux et horizontaux de 1 pixel doit apparaître en gris au lieu de noir, plutôt qu'en flou. –