Сохраняйте ширину линии при масштабировании всех точек в контексте с помощью CGAffineTransform.
-
22-09-2019 - |
Вопрос
у меня есть CGPath
в некоторой системе координат, которую я хотел бы нарисовать.Для этого необходимо масштабировать старую систему координат на систему контекста.Для этой цели я использую CGContextConcatCTM()
который преобразует все точки должным образом.Но, поскольку это операция масштабирования, ширина горизонтальной/вертикальной линии изменяется на.Например.масштаб 10 по оси x и 1 по оси y приведет к тому, что вертикальные линии будут в 10 раз толще горизонтальных.Есть ли способ сохранить простоту использования матриц перевода (например, CGAffineTransform
), но не масштабируя при этом ширину линий, например.функция типа CGPathApplyAffineTransformToPoints
?
Ваше здоровье
Мистер Маг
Решение
Вы можете использовать CGPathApply
для перебора элементов пути.Это немного сложнее, чем просто однострочный код, но если вы упаковаете его в простую вспомогательную функцию, это может оказаться для вас полезным.Вот одна из версий, которая создает новый путь и преобразует его:
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;
}
}
Чтобы использовать его, вы должны сделать (это часть, которую я бы поместил во вспомогательную функцию):
PathTransformInfo info;
info.path = CGPathCreateMutable();
info.transform = CGAffineTransformMakeScale(2, 1);
CGPathApply(originalPath, &info, PathTransformer);
Преобразованный путь находится в info.path
в этот момент.
Другие советы
Выполните преобразование при добавлении пути, но затем удалите преобразование, прежде чем обводить контур.Вместо этого:
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
Сделай это:
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);