Como configurar um sistema de coordenadas quartz2d de usuário com escala que evita desenho difuso?
-
21-09-2019 - |
Pergunta
Este tópico foi arranhado uma ou duas vezes, mas ainda estou intrigado. E o Google também não foi amigável.
Como o Quartz permite sistemas de coordenadas arbitrárias usando transformações afins, quero poder desenhar coisas como plantas de piso usando coordenadas da vida real, por exemplo.
Então, basicamente, para um exemplo, quero escalar a visualização para que, quando desenho um retângulo de 10x10 (pense em uma caixa de 10 polegadas, por exemplo), recebo um retângulo de 60x60 pixels.
Funciona, exceto que o retângulo que recebo é bastante confuso. Outra pergunta aqui obteve uma resposta que explica o porquê. No entanto, não tenho certeza se entendi essa razão e, além disso, não sei como corrigi -lo. Aqui está o meu código:
Eu defino meu sistema de coordenadas no meu awakeFromNib
Método de exibição personalizado:
- (void) awakeFromNib {
CGAffineTransform scale = CGAffineTransformMakeScale(6.0, 6.0);
self.transform = scale;
}
E aqui está minha rotina de sorteio:
- (void)drawRect:(CGRect)rect {
CGContextRef context = UIGraphicsGetCurrentContext();
CGRect r = CGRectMake(10., 10., 10., 10.);
CGFloat lineWidth = 1.0;
CGContextStrokeRectWithWidth(context, r, lineWidth);
}
A praça que recebo é escalada muito bem, mas totalmente confusa. Brincando com lineWidth
não ajuda: quando lineWidth
é definido menor, fica mais leve, mas não mais nítido.
Então, existe uma maneira de configurar uma visão de ter um sistema de coordenadas em escala, para que eu possa usar minhas coordenadas de domínio? Ou devo voltar e implementar a escala nas minhas rotinas de desenho?
Observe que esse problema não ocorre para tradução ou rotação.
Obrigado
Solução 2
Bem, como frequentemente, explicar o problema me leva a uma solução.
O problema é que a propriedade View Transform é aplicada a ela depois que ela foi atraída para um buffer um pouco. A transformação de escala deve ser aplicada antes de desenhar, ou seja. no drawRect
método. Então arranhe o awakeFromNib
Eu dei, e aqui está um drawrect correto:
- (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);
}
Outras dicas
O retângulo [acariciado] que recebo é bastante confuso.
Geralmente, isso ocorre porque você plotou o retângulo em coordenadas de número inteiro e sua largura de linha é 1.
Em PostScript (e, portanto, em seus descendentes: Appkit, PDF e Quartz), as unidades de desenho são inadimplentes para os pontos, sendo 1 ponto exatamente 1/72 polegada. O Mac e o iPhone atualmente* tratam todos os pontos como 1 pixels, independentemente da resolução real das tela (s), portanto, em um sentido prático, os pontos (por padrão, no Mac e iPhone) são iguais a pixels.
Em PostScript e seus descendentes, as coordenadas integrais são executadas entre os pontos. 0, 0, por exemplo, é o canto inferior esquerdo do ponto inferior esquerdo. 1, 0 é o canto inferior direito do mesmo ponto (e o canto inferior esquerdo do ponto próximo à direita).
Um derrame está centrado no caminho que você está acariciando. Assim, metade estará dentro do caminho, metade do lado de fora.
No mundo (conceitual) de 72 dpi do Mac, esses dois fatos se combinam para produzir um problema. Se 1 pt for igual a 1 pixels e você aplica um golpe de 1 % entre dois pixels, metade do golpe atingirá cada um desses pixels.
O quartzo, pelo menos, renderá isso pintando a cor atual em ambos os pixels na metade do alfa da cor. Determina isso por quanto do pixel é coberto pelo derrame conceitual; Se você usou uma largura da linha de 1,5-pt, metade disso é de 0,75 pt, que é de três quartos de cada pixel de 1 pt, portanto a cor será renderizada em 0,75 alfa. Isso, é claro, vai para a conclusão natural: se você usar uma largura da linha de 2-pt, cada pixel é completamente coberto, então o alfa será 1. É por isso que você pode ver esse efeito com um golpe de 1 pt e não um 2-PT AVC.
Existem várias soluções alternativas:
Tradução de meio ponto: exatamente o que diz na caixa, você traduz e direito a meio ponto, compensando a divisão mencionada em 1 cut-cut-cut-cut-cut.
Isso funciona em casos simples, mas flocos quando você envolve outras transformações de coordenadas, exceto traduções de ponto inteiro. Ou seja, você pode traduzir por 30, 20 e ainda funcionará, mas se você traduzir por 33+1/3, 25.252525…, ou se você escalar ou girar, sua tradução de meio ponto será inútil .
AVC interno: Clip primeiro e depois duplique a largura da linha (porque você só vai desenhar metade) e depois o golpe.
Isso pode exigir malabarismo com o GSTATE se você tiver muitos outros desenhos, pois não deseja que esse caminho de recorte afete seu outro desenho.
Expertação externa: essencialmente o mesmo que um golpe interno, exceto que você reverte o caminho antes de cortar.
Pode ser melhor (menos malabarismo com GState) do que um golpe interno, se tiver certeza de que os caminhos que você deseja derrotar não se sobrepõem. Por outro lado, se você também deseja preencher o caminho, o GState malabarismo retorna.
*Isso não vai durar para sempre. A Apple está deixando dicas há algum tempo que eles vão mudar pelo menos a resolução de desenho do MAC em algum momento. A base da API para essa mudança está praticamente tudo lá agora; É tudo uma questão de maçã jogar o interruptor.