Préserver la largeur de la ligne tout en réduisant tous les points dans le contexte avec CGAffineTransform
-
22-09-2019 - |
Question
J'ai un CGPath
dans certains système de coordonnées que je voudrais dessiner. Cela implique l'extension de l'ancien système de coordonnées sur l'un du contexte. A cet effet, j'utilise CGContextConcatCTM()
qui se transforme de tous les points comme il se doit. Mais, comme il est une opération de mise à l'échelle, les largeurs de lignes verticales / horizontales sont changés à. Par exemple. une échelle de 10 dans la direction x, mais de 1 dans la direction y conduiraient à des lignes verticales étant 10 fois plus épaisse que celles horizontales. Y at-il un moyen de garder la facilité d'utilisation de matrices de traduction (par exemple CGAffineTransform
) mais pas la ligne mise à l'échelle des largeurs en même temps, par exemple une fonction comme CGPathApplyAffineTransformToPoints
?
Vive
MrMage
La solution
Vous pouvez utiliser CGPathApply
pour parcourir les éléments dans un chemin. Il est un peu plus complexe qu'un simple one-liner, mais si vous l'emballer dans une simple fonction d'aide, il peut être utile pour vous. Voici une version qui crée un nouveau chemin et la transforme:
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;
}
}
Pour l'utiliser, vous feriez (ce qui est la partie que je mettrais dans une fonction d'aide):
PathTransformInfo info;
info.path = CGPathCreateMutable();
info.transform = CGAffineTransformMakeScale(2, 1);
CGPathApply(originalPath, &info, PathTransformer);
Le chemin est transformé en info.path
à ce stade.
Autres conseils
Faites la transform lorsque vous ajoutez le chemin, mais enlever la transformation avant de la course le chemin. Au lieu de cela:
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
Pour ce faire:
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);