Один шаг аффинного преобразования для вращения вокруг точки? - PullRequest
42 голосов
/ 26 ноября 2011

Как я могу сделать аффинное преобразование Core Graphics для вращения вокруг точки x, y угла a, используя только один вызов CGAffineTransformMake () плюс триггерные функции math.h, такие как sin (), cos () и т. Д. и никаких других вызовов CG.

Другие ответы здесь, похоже, касаются использования нескольких стековых преобразований или многошаговых преобразований для перемещения, вращения и перемещения с использованием нескольких вызовов Core Graphics. Эти ответы не соответствуют моим конкретным требованиям.

Ответы [ 5 ]

114 голосов
/ 16 декабря 2011

Вращение угла a вокруг точки (x, y) соответствует аффинному преобразованию:

CGAffineTransform transform = CGAffineTransformMake(cos(a),sin(a),-sin(a),cos(a),x-x*cos(a)+y*sin(a),y-x*sin(a)-y*cos(a));

Возможно, вам потребуется подключить -a вместо зависимости от того, хотите ли вы вращениебыть по часовой стрелке или против часовой стрелки.Кроме того, вам может понадобиться подключить -y вместо y в зависимости от того, перевернута ли ваша система координат.

Кроме того, вы можете выполнить одно и то же в трех строках кода, используя:

CGAffineTransform transform = CGAffineTransformMakeTranslation(x, y);
transform = CGAffineTransformRotate(transform, a);
transform = CGAffineTransformTranslate(transform,-x,-y);

Если вы применяете это к представлению, вы также можете просто использовать преобразование вращения через CGAffineTransformMakeRotation (a), при условии, что вы установили свойство anchorPoint слоя представления, чтобы отразить точку, вокруг которой вы хотите повернуть.Однако звучит так, будто вы не заинтересованы в применении этого к представлению.

Наконец, если вы применяете это к неевклидову 2D-пространству, вы можете вообще не захотеть аффинное преобразование.Аффинные преобразования - это изометрии евклидова пространства, что означает, что они сохраняют стандартное евклидово расстояние, а также углы.Если ваше пространство не является евклидовым, то преобразование, которое вы хотите, может на самом деле не быть аффинным, или если оно аффинно, матрица для вращения может быть не такой простой, как то, что я написал выше с помощью sin и cos.Например, если вы находитесь в гиперболическом пространстве, вам может потребоваться использовать гиперболические тригонометрические функции sinh и cosh, а также различные знаки + и - в формуле.

PS Я также хотел бы напомнить любому, кто читает этодалеко, что «аффинность» произносится с коротким «а», как в «спросить», а не с длинным «а», как в «состоянии».Я даже слышал, как сотрудники Apple неправильно произносили это в своих выступлениях на WWDC.

2 голосов
/ 11 декабря 2018

для Swift 4

print(x, y) // where x,y is the point to rotate around
let degrees = 45.0
let transform = CGAffineTransform(translationX: x, y: y)
    .rotated(by: degrees * .pi / 180)
    .translatedBy(x: -x, y: -y)
2 голосов
/ 06 января 2016

Для таких, как я, которые изо всех сил пытаются найти полное решение, чтобы повернуть изображение и правильно его масштабировать, чтобы заполнить вмещающий кадр, через пару часов это самое полное и безупречное решение, которое у меня есть получен.

Хитрость здесь в том, чтобы перевести исходную точку перед любой трансформацией (как масштаб, так и вращение). После этого вам нужно объединить два преобразования, чтобы получить полное аффинное преобразование.

Я упаковал все решение в подкласс CIFilter, который вы можете найти здесь .

После соответствующей части кода:

CGFloat a = _inputDegree.floatValue;
CGFloat x = _inputImage.extent.size.width/2.0;
CGFloat y = _inputImage.extent.size.height/2.0;

CGFloat scale = [self calculateScaleForAngle:GLKMathRadiansToDegrees(a)];

CGAffineTransform transform = CGAffineTransformMakeTranslation(x, y);
transform = CGAffineTransformRotate(transform, a);
transform = CGAffineTransformTranslate(transform,-x,-y);


CGAffineTransform transform2 = CGAffineTransformMakeTranslation(x, y);
transform2 = CGAffineTransformScale(transform2, scale, scale);
transform2 = CGAffineTransformTranslate(transform2,-x,-y);

CGAffineTransform concate   = CGAffineTransformConcat(transform2, transform);
0 голосов
/ 28 мая 2018

Используйте слой вида и опорную точку.например,

view.layer.anchorPoint = CGPoint(x:0,y:1.0)
0 голосов
/ 26 ноября 2011

Проверьте эту ссылку: Поворот iPhone вокруг точки .Это может помочь вам.Внизу статьи есть раздел «Изменить точку привязки».Это, вероятно, больше всего подходит для ваших нужд, хотя есть некоторая компенсация, которая должна быть сделана, чтобы не сместить вид.

...