Préserver la largeur de la ligne tout en réduisant tous les points dans le contexte avec CGAffineTransform

StackOverflow https://stackoverflow.com/questions/1798441

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

Était-ce utile?

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);
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top