Один шаг аффинного преобразования для вращения вокруг точки?

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

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

Ответ 1

Вращение угла 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 вместо 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 вместе с разными + и-знаками в формуле.

P.S. Я также хотел напомнить всем, кто читает это далеко, что "аффинный" произносится с коротким "а", как в "спросе", а не с длинным "а", как в "способном". Я даже слышал, как сотрудники Apple неправильно истолковали это на своих переговорах по WWDC.

Ответ 2

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

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

Я собрал все решение в подклассе 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);

Ответ 3

Посмотрите эту ссылку: Поворот iPhone View Around a point. Это может вам помочь. В нижней части статьи есть раздел под названием "Изменить опорную точку". Это, вероятно, наиболее подходит для ваших нужд, хотя есть некоторая компенсация, которая должна быть выполнена, чтобы не компенсировать представление.

Ответ 4

для 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)

Ответ 5

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

view.layer.anchorPoint = CGPoint(x:0,y:1.0)