Layer Geometry and Transforms
OSXDEV
Core Animation Programming Guide로 이동
이 장에서는 레이어의 기하학적 구성과 그것들의 상호작용 그리고 변환 행렬이 복잡한 시각효과를 만들어내는 법을 설명한다.
목차 |
[편집] 레이어 좌표계
레이어의 위치와 크기는 쿼츠 그래픽스 환경이 사용하는 것과 동일한 좌표계로 표현된다. 기본적으로, 그래픽스 환경의 원점 (0.0, 0.0)은 좌하단에 위치하고 있으며, 값은 위쪽과 오른쪽으로 좌표계 단위로 증가하는 부동소숫점 숫자로 지정된다. 좌표계 단위는 가로세로 1.0을 가지는 정사각형이다.
모든 레이어 인스턴스는 그 자신의 좌표계를 정의하고 관리하며, 이 좌표계에 상대적으로 모든 서브레이어들이 위치하고, 드로잉이 이루어진다. 이 좌표계에 의해 이루어진다. 한 레이어 좌표계에서 다른 좌표계로 점과 사각형을 변환하는 메소드가 제공된다. 레이어의 좌표계는 그 레이어의 서브 레이어를 포함한 모든 컨텐트의 기반 좌표계로 인식된다.
[편집] 레이어의 평면 지정하기
레이어들과 레이어-트리의 관계가 코코아에서 뷰와 뷰 계층구조의 관계와 많은 면에서 유사한 반면, 레이어의 기하평면을 표현하는 방식은 약간 다르고 조금 더 단순하다. 레이어의 트랜스포메이션을 포함한 모든 평면 프라퍼티들은 암묵적으로implicitly 그리고 명시적으로explicitly 애니메이션이 가능하다.
<그림 1>은 레이어의 평면을 지정하는 데 사용하는 프라퍼티를 보여준다.
그림 1. CALayer 기하평면 프라퍼티
position 프라퍼티는 레이어의 위치를 슈퍼레이어에 상대적으로 지정하는 CGPoint 값이며, 슈퍼레이어의 좌표계로 표현된다.
bound 프라퍼티는 레이어의 크기 (bounds.size)와 원점 (bounds.origin)을 제공하는 CGRect값이다. 바운드 원점은 레이어의 드로잉 메소드를 오버라이드 할 때 그래픽 원점으로 사용된다.
레이어는 암묵적인implicit frame을 가지고 있다. 이것은 position, bounds, anchorPoint 그리고 transform 프라퍼티의 함수이다. 새로운 프레임 사각형을 설정하는 것은 레이어의 position과 bounds 프라퍼티 또한 변경하는 것이지만, 프레임 그 자신은 저장되지 않는다. 새롭게 설정된 프레임 사각형이 바운드 원점을 침범한다면, 바운드 사이즈는 프레임의 사이즈로 설정된다. 레이어의 위치는 앵커 포인트에 상대적으로 적당한 위치에 설정된다. frame 프라퍼티 값을 읽으면 position, bounds 그리고 anchorPoint 프라퍼티에 상대적으로 계산된다.
anchorPoint 프라퍼티는 레이어의 바운드 내에서 position 좌표에 해당하는 위치를 지정하는 CGPoint값이다. 앵커 포인트는 바운드가 position 프라퍼티에 상대적으로 위치하는 지를 지정하기도 하고 트랜스폼이 적용되는 곳의 역할도 한다. 이것은 단위 좌표계로 표현된다 - 레이어 바운드의 좌하단은 0.0,0.0이며 우상단은 1.0,1.0이다.
레이어의 프레임을 지정할 때, position은 앵커 포인트에 상대적으로 설정된다. 레이어의 위치를 지정하면, bounds는 앵커 포인트에 상대적으로 설정된다.
<그림 2>는 앵커 포인트에 대한 예를 3가지 보여준다.
그림 2. 앵커 포인트 값 3개
anchorPoint의 기본값은 (0.5,0.5)로서 레이어의 바운드 중심점에 해당한다(그림 2의 점 A). 이 값의 앵커 포인트는 트랜스폼이 레이어의 중앙을 따라 적용되도록 한다. 점 B는 (0.0, 0.5)로 설정된앵커 포인트를 보여준다; 트랜스폼은 레이어의 왼쪽 모서리 중간을 따라 적용될 것이다. 마지막으로, 점C (1.0, 0.0)는 트랜스폼이 레이어의 우하단을 따라 적용되도록 한다.
<그림 3>은 frame, bounds, position 그리고 anchorPoint 프라퍼티들간의 관계를 보려준다.
그림 3. (0.5, 0.5) 원점의 레이어
이 예제에서 anchorPoint는 레이어의 중심에 해당하는, 기본값 (0.5, 0.5)로 설정되었다. 레이어의 position은 (100.0, 100.0), 그리고 bounds는 사각형 (0.0, 0.0, 120.0, 80.0)으로 설정되었다. 이것은 프레임 프라퍼티가 (40.0, 60.0, 120.0, 80.0)으로 계산되는 결과를 낳는다.
새 레이어를 만들었고, 레이어의 프레임 프라퍼티만 (40.0, 60.0, 120.0, 80.0)으로 설정한다면, position 프라퍼티는 자동적으로 (100.0, 100.0)으로, bounds 프라퍼티는 (0.0, 0.0, 120.0, 80.0)으로 설정된다.
<그림 4>는 <그림 3>의 레이어의 frame 사각형과 동일한 레이어이다. 그러나, 레이어의 anchorPoint는 레이어의 좌하단에 해당하는(0.0, 0.0)으로 설정되었다.
그림 4. (0.0, 0.0) 원점의 레이어
프레임이 (40.0, 60.0, 120.0, 80.0)으로 설정되면, bounds 프라퍼티의 값은 같지만, position 프라퍼티의 값은 변경된다.
레이어 평면이 코코아의 뷰와 다른 또 한가지는 레이어의 모서리를 둥글게 하기 위한 반경을 지정할 수 있다는 것이다. cornerRadius 값은 레이어가 컨텐트를 그리고, 서브레이어를 잘라내고, 경계선과 그림자를 드리는 데 사용한다.
zPosition 프라퍼티는 레이어의 z-축 위치를 지정한다. zPosition은 그 인접 레이어에 상대적인 시각적 위치를 설정하기 위해 사용한다. 서브레이어 배열에서 레이어의 순서를 재정렬 하는 것 대신해서 인접 레이어와서 순서 정렬에 사용하면 안된다.
[편집] 레이어의 평면 변형하기
레이어가 만들어지고 나면 레이어의 평면을 행렬 변환을 이용해서 트랜스폼 할 수 있다. 정방형 삼차원 트랜스폼 (4*4 CGFloat 행렬값)을 가지는 CATransform3D 데이터 구조체를 이용해 회전, 확대/축소, 이동, 기울이기와 원근감을 주는 트랜스폼을 레이어에 줄 수 있다.
두개의 레이어 프라퍼티가 트랜스폼 행렬을 정의한다: transform과 sublayerTransform. transform 프라퍼티에 의해 지정되는 행렬은 레이어와 레이어의 anchorPoint에 연관된 서브레이어들에 적용된다. sublayerTransform 프라퍼티에 의해 지정되는 행렬은 레이어 그 자신에게는 적용되지 않고, 레이어의 서브레이어에만 적용된다.
CATransform3D 데이터 구조체는 다음과 같은 방법으로 만들고 수정할 수 있다.
- CATransform3D 함수를 사용
- 데이터 구조체 멤버들을 직접 수정해서
- 키-값 코딩과 키패쓰를 이용해서
CATransform3DIdentity 상수는 항등행렬로서, 크기조절, 회전, 기울이기 혹은 원근이 적용되지 않는 행렬이다. 레이어에 항등행렬을 적용하면 레이어의 기본 평면을 디스플레이 하게 될 것이다.
[편집] 변형함수들
코어 애니메이션에서 사용가능한 트랜스폼 함수들은 행렬에 작용한다. 함수들(표 1)을 사용해서 행렬을 구성해 낸 후 나중에 레이어나 서브레이어에 transform, sublayerTaansform 메소드로 행렬을 적용할 수 있다. 트랜스폼 함수는 행렬에 적용할 수도 있고, CATransform3D 데이터 구조체를 리턴할 수도 있다. 이것은 손쉽게 재사용할 수 있는, 단순/복잡한 트랜스폼을 구성 한다.
표1. 이동, 회전, 크기조절을 위한 CATransform3D 트랜스폼 함수
| 함수 | 사용 |
|---|---|
| CATransform3DMakeTranslation | '(tx, ty, tz)'. t' = [1 0 0 0; 0 1 0 0; 0 0 1 0; tx ty tz 1]로 이동하는 트랜스폼을 리턴한다. |
| CATransform3DTranslate | 't'를 '(tx, ty, tz)'로 이동시키고 *t' = translate(tx, ty, tz) *t의 결과를 리턴한다 |
| CATransform3DMakeScale | `(sx, sy, sz)': * t' = [sx 0 0 0; 0 sy 0 0; 0 0 sz 0; 0 0 0 1]로 스케일하는 트랜스폼을 리턴한다. |
| CATransform3DScale | 't'를 '(sx, sy, sz)'로 이동시키고 *t' = scale(sx, sy, sz) *t의 결과를 리턴한다 |
| CATransform3DMakeRotation | 벡터 '(x,y,x)'를 'angle'라디안만큼 회전시키는 트랜스폼을 리턴한다. 벡터가 0의 길이값을 가지고 있으면 identity 트랜스폼이 리턴된다. |
| CATransform3DRotation | t를 벡터 '(x,y,x)'에 대해 'angle'라디안만큼 회전시키고 그 결과를 리턴한다. t' = rotation(angle, x, y, z) * t. |
회전의 각도는 degree가 아닌 radian으로 지정된다. 다음 함수를 이용해서 radian과 degree사이의 변환을 할 수 있다.
CGFloat DegreesToRadians(CGFloat degrees) {return degrees * M_PI / 180;};
CGFloat RadiansToDegrees(CGFloat radians) {return radians * 180 / M_PI;};
코어 애니메이션은 행렬을 반전하는 트랜스폼 함수인 CATransform3DInvert를 제공한다. 반전은 일반적으로 이미 변형된 오브젝트 내에서 역 트랜스포메이션을 얻기 위해 사용한다. 행렬에 의해 변환된 값을 복구하는데 사용하면 유용하다: 행렬을 반전한 뒤 반전된 행렬을 곱하면 원래의 값이 산출된다.
CATransform3D이 표현 가능하다면, CATransform3D 행렬을 CGAffineTransform 행렬로 바꾸는 함수도 제공된다.
표2. CGAffineTransform 전환을 위한 CATransform3D 변환 함수
| 함수 | 사용 |
|---|---|
| CATransform3DMakeAffineTransform | 넘어온 affine 트랜스폼과 같은 효과를 가지는 CATransform3D를 리턴한다 |
| CATransform3DIsAffine | 넘어온 CATransform3D가 affine 트랜스폼으로 나타내진다면 YES를 리턴한다. |
| CATransform3DGetAffineTransform | `(sx, sy, sz)': * t' = [sx 0 0 0; 0 sy 0 0; 0 0 sz 0; 0 0 0 1]로 스케일하는 트랜스폼을 리턴한다. |
변환 행렬을 항등행렬 또는 다른 변환 행렬과 비교하는 함수도 제공된다
표3. 동일성을 테스트 하기 위한 CATransform3D 변환 함수
| 함수 | 사용 |
|---|---|
| CATransform3DIsIdentity | 트랜스폼이 항등 변환이면 YES를 리턴한다. |
| CATransform3DEqualToTransform | 두개의 변환이 같다면 YES를 리턴한다. |
[편집] Modifying the Transform Data Structure
다른 데이터 구조체들처럼 CATransform3D 데이터 구조체의 멤버들 중 어떤 값이든 수정할 수 있다. Listing 1은 CATransform3D 데이터 구조체의 정의를 보여준다. 구조체의 멤버들은 해당 행렬 위치를 나타낸다.
Listing 1 CATransform3D 구조체
struct CATransform3D
{
CGFloat m11, m12, m13, m14;
CGFloat m21, m22, m23, m24;
CGFloat m31, m32, m33, m34;
CGFloat m41, m42, m43, m44;
};
typedef struct CATransform3D CATransform3D;
Listing 2의 예는 원근 트랜스폼에 해당하는 CATransform3D를 설정하는 법을 보여준다.
Listing 2 CATransform3D 데이터 구조체를 직접 수정하기
CATransform3D aTransform = CATransform3DIdentity; // zDistance 값은 변환의 sharpness에 영향을 준다. zDistance = 850; aTransform.m34 = 1.0 / -zDistance;
[편집] Modifying a Transform Using Key Paths
코어 애니메이션은 키-값 코딩 프로토콜을 확장하여 레이어의 CATransform3D 행렬의 값들을 키 패쓰를 통해 읽고 쓰게 해 준다. 표4는 레이어의 transform과 sublayerTransform 프라퍼티가 키-값 코딩과 오브저빙에 적용할 수 있는 키 패쓰를 설명한다.
Table 4 CATransform3D 키 패쓰
| 필드 키 패쓰 | 설명 |
|---|---|
| rotation.x | x축 방향 라디안 값의 회전 |
| rotation.y | y축 방향 라디안 값의 회전 |
| rotation.z | z축 방향 라디안 값의 회전 |
| rotation | z축 방향 라디안 값의 회전. rotation.z 필드를 설정하는 것과 동일하다. |
| scale.x | x축 방향 크기 조정 값 |
| scale.y | y축 방향 크기 조정 값 |
| scale.z | z축 방향 크기 조정 값 |
| scale | 세가지 크기조정 값의 평균값 |
| translation.x | x축 방향 이동 |
| translation.y | y축 방향 이동 |
| translation.z | z축 방향 이동 |
| translation | x축과 y축 방향으로의 이동. 값은 NSSize이거나 CGSize이다. |
구조체 필드 키 패쓰를 Objective-C 2.0 프라퍼티를 이용해서 지정할 수 없다. 다음과 같은 코드는 동작하지 않는다:
myLayer.transform.rotation.x = 0
그 대신 아래와 같이 setValue:forKeyPath: 혹은 valueForKeyPath:를 사용해야 한다.
[myLayer setValue:[NSNumber numberWithInt:0] forKeyPath:@"transform.rotation.x"];








