2011-11-26 10 views
35

¿Cómo puedo hacer una transformación afín Core Graphics para la rotación alrededor de un punto x, y de ángulo a, usando solo una llamada a CGAffineTransformMake() más funciones trigonométricas math.h como sin(), cos(), etc. y ninguna otra llamada CG.Transformación afín de un paso para la rotación alrededor de un punto?

Otras respuestas aquí parecen ser sobre el uso de múltiples transformaciones apiladas o transformaciones de varios pasos para mover, rotar y mover, utilizando múltiples llamadas de gráficos principales. Esas respuestas no cumplen mis requisitos específicos.

+2

¿Por qué necesita una sola llamada a 'CGAffineTransformMake()'? Las llamadas apiladas producen exactamente los mismos resultados, excepto que lo hacen de una manera que es legible y tiene sentido.Si realmente desea hacerlo en una sola llamada, terminará replicando la misma matemática utilizada en las llamadas apiladas, para absolutamente no beneficiarse. –

+3

¿Qué requisitos podría ser eso? Puede combinar esas transformaciones "apiladas" en una CGAffineTransform usando CGAffineTransformConcat. El resultado será el mismo que las fórmulas para los componentes individuales, y los cálculos involucrados serán los mismos internamente, o posiblemente más optimizados en el caso de CGAffineTransformConcat. – morningstar

+0

Quiero que las ecuaciones matriciales se usen en un objeto modelo que coincida pero no en un espacio geométrico diferente (no necesariamente euclidiano). – hotpaw2

Respuesta

101

una rotación de ángulo a alrededor del punto (x, y) corresponde a la transformación afín:

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)); 

Es posible que tenga que conectar en -a en lugar de una función de si desea que la rotación sea en sentido horario o antihorario. Además, es posible que deba enchufar -y en lugar de y- dependiendo de si su sistema de coordenadas está o no al revés.

Además, se puede lograr exactamente lo mismo en tres líneas de código usando:

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

Si se le solicita a un punto de vista, también se puede utilizar simplemente una rotación transformar a través de CGAffineTransformMakeRotation (a), siempre que establezca la propiedad anchorPoint de la capa de la vista para reflejar el punto que desea rotar. Sin embargo, parece que no está interesado en aplicar esto a una vista.

Finalmente, si está aplicando esto a un espacio 2D no euclidiano, es posible que no desee una transformación afín en absoluto. Las transformaciones afines son isometrías del espacio euclidiano, lo que significa que conservan la distancia euclidiana estándar, así como los ángulos. Si su espacio no es euclidiano, entonces la transformación que desea puede no ser afín, o si es afín, la matriz para la rotación puede no ser tan simple como lo que escribí arriba con sin y cos. Por ejemplo, si estuvieras en un espacio hiperbólico, podrías necesitar usar las funciones trigonométricas hiperbólicas sinh y cosh, junto con diferentes signos + y - en la fórmula.

P.S. También quería recordarle a cualquiera que haya leído hasta aquí que "afín" se pronuncia con una "a" corta como en "preguntar", no una "a" larga como en "capaz". Incluso he escuchado a los empleados de Apple pronunciarlo mal en sus conversaciones de WWDC.

+1

¿Qué es 'a' exactamente? – jjxtra

+1

'a' es un ángulo en radianes parece – Curtis

+2

Si va a dar consejos sobre la pronunciación, también debe especificar si es -fino como en "fino" o -fino como en "feen". Pero tal vez soy el único en equivocarme con esa parte. : -/ –

1

Echa un vistazo a este enlace: Rotating an iPhone View Around a Point. Puede ser de ayuda. Hacia la parte inferior del artículo, hay una sección titulada "Cambiar el punto de anclaje". Esto es probablemente lo más adecuado para sus necesidades, aunque se debe hacer alguna compensación para no compensar la vista.

2

Para aquellos como yo, que están luchando en la búsqueda de una solución completa para rotar una imagen y escalarla adecuadamente, para llenar el marco contenedor, después de un par de horas, esta es la solución más completa e impecable que yo Obtuvo.

El truco aquí es traducir el punto de referencia, antes de cualquier trasformación involucrada (tanto la escala como la rotación). Después de eso, debes concatenar las dos transformaciones para obtener una transformación afín completa.

He empacado la solución completa en una subclase CIFilter que puede gist here.

Después de la parte pertinente del código:

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); 
Cuestiones relacionadas