Preserve a largura da linha enquanto escala todos os pontos no contexto com CGAFFINETRANSFORM
-
22-09-2019 - |
Pergunta
eu tenho um CGPath
Em algum sistema de coordenadas que eu gostaria de desenhar. Isso envolve escalar o antigo sistema de coordenadas para o contexto. Para esse fim, eu uso CGContextConcatCTM()
que transforma todos os pontos como deveria. Mas, como é uma operação de escala, as larguras da linha horizontal/vertical são alteradas para. Por exemplo, uma escala de 10 na direção x, mas de 1 na direção y levaria a linhas verticais 10 vezes mais espessa que as horizontais. Existe uma maneira de manter a facilidade de uso de matrizes de tradução (por exemplo CGAffineTransform
), mas não as larguras da linha de escala ao mesmo tempo, por exemplo, uma função como CGPathApplyAffineTransformToPoints
?
Felicidades
Mrmage
Solução
Você pode usar CGPathApply
para iterar através dos elementos em um caminho. É um pouco mais complexo do que apenas uma linha, mas se você o empacotar em uma função auxiliar simples, poderá ser útil para você. Aqui está uma versão que cria um novo caminho e o transforma:
typedef struct {
CGMutablePathRef path;
CGAffineTransform transform;
} PathTransformInfo;
static void
PathTransformer(void *info, const CGPathElement *element)
{
PathTransformInfo *transformerInfo = info;
switch (element->type) {
case kCGPathElementMoveToPoint:
CGPathMoveToPoint(transformerInfo->path, &transformerInfo->transform,
element->points[0].x, element->points[0].y);
break;
case kCGPathElementAddLineToPoint:
CGPathAddLineToPoint(transformerInfo->path, &transformerInfo->transform,
element->points[0].x, element->points[0].y);
break;
case kCGPathElementAddQuadCurveToPoint:
CGPathAddQuadCurveToPoint(transformerInfo->path, &transformerInfo->transform,
element->points[0].x, element->points[0].y,
element->points[1].x, element->points[1].y);
break;
case kCGPathElementAddCurveToPoint:
CGPathAddCurveToPoint(transformerInfo->path, &transformerInfo->transform,
element->points[0].x, element->points[0].y,
element->points[1].x, element->points[1].y,
element->points[2].x, element->points[2].y);
break;
case kCGPathElementCloseSubpath:
CGPathCloseSubpath(transformerInfo->path);
break;
}
}
Para usá -lo, você faria (esta é a parte que eu colocaria dentro de uma função ajudante):
PathTransformInfo info;
info.path = CGPathCreateMutable();
info.transform = CGAffineTransformMakeScale(2, 1);
CGPathApply(originalPath, &info, PathTransformer);
O caminho transformado está em info.path
neste ponto.
Outras dicas
Faça a transformação quando adicionar o caminho, mas remova a transformação antes de acariciar o caminho. Em vez disso:
CGContextSaveGState(ctx);
CGContextScaleCTM(ctx, 10, 10); // scale path 10x
CGContextAddPath(ctx, somePath);
CGContextSetStrokeColorWithColor(ctx, someColor);
CGContextSetLineWidth(ctx, someWidth); // uh-oh, line width is 10x, too
CGContextStrokePath(ctx);
CGContextRestoreGState(ctx); // back to normal
Fazem isto:
CGContextSaveGState(ctx);
CGContextScaleCTM(ctx, 10, 10); // scale path 10x
CGContextAddPath(ctx, somePath);
CGContextRestoreGState(ctx); // back to normal
CGContextSetStrokeColorWithColor(ctx, someColor);
CGContextSetLineWidth(ctx, someWidth);
CGContextStrokePath(ctx);