-
Notifications
You must be signed in to change notification settings - Fork 0
Home
Welcome to the ImageControlView wiki!
이 위키에서는 가장 어려웠던 "뷰 회전"에 대해서 기록할 것 입니다.
사용자가 View를 회전할 때, 취하는 액션은 크게 세 가지 입니다.
-
ACTION_DOWN으로 회전 아이콘 터치
-
ACTION_MOVE로 원하는 각도만큼 드래그
-
ACTION_UP으로 끝마침
이 세 가지를 그림으로 표현하면 다음과 같습니다.

또한 뷰의 회전은 뷰의 중심을 기준으로 이루어 져야 합니다.
따라서 우리가 회전하기 위해서는 3 가지 지점의 위치를 알아야 합니다.
-
View의 중심 위치
-
사용자가 첫 번째로 ACTION_DOWN을 한 위치(==View 회전 버튼의 위치)
-
현재 변화하고 있는 사용자의 ACTION_MOVE의 위치
이 세 가지의 위치를 점으로 가지는 삼각형은 아래과 같이 될 것입니다.

우린 그림에 나와 있는 변화된 각도 a를 구해야 합니다.
위의 삼각형의 세 꼭짓점의 좌표는 아래의 방법으로 쉽게 구할 수 있습니다.
val centerX = this.x + this.width / 2
val centerY = this.y + this.height / 2
val touchX = event.x + this.x + view.x
val touchY = event.y + this.y + view.y
val buttonX = this.x + view.x + view.width / 2
val buttonY = this.y + view.y + view.height / 2그 다음 두 꼭짓점의 길이는 피타고라스의 정리에 의해 쉽게 구할 수 있습니다.
아래는 피타고라스 정리를 이용하여 두 좌표의 거리를 구하는 함수 입니다.
private fun getDistanceBetweenTwoPosition(x1:Float,y1:Float,x2:Float,y2:Float):Float{
return sqrt((x2-x1).pow(2)+(y2-y1).pow(2))
}그 다음 우리는 변화된 각도 a를 구해야 합니다.
각도 a를 구하기 위해서 제 2 코사인 법칙을 활용합니다.
제 2 코사인 법칙은 아래와 같습니다.

이를 정리하면 아래와 같이 됩니다.

이 다음 cos(a)를 acos에 넣어 Degree로 바꾼다면 우리가 원하는 각도를 구할 수 있게 됩니다.
최종적으로 위 공식을 구현한 코드는 아래와 같습니다.
//a^2 = b^2 + c^2 - 2bc*cosA
//cosA = (b^2 + c^2 - a^2) / (2bc)
val cosA =
(centerAndButtonDistance.pow(2)+centerAndTouchDistance.pow(2)-buttonAndTouchDistance.pow(2))/(2*centerAndButtonDistance*centerAndTouchDistance)
val currDegree=Math.toDegrees(acos(cosA).toDouble()).toFloat()이로서 사용자가 회전한 순수한 각도 값을 구했습니다.
하지만 이는 부호가 없는 그저 사이의 각도 입니다.
시계 방향 회전과 반시계 방향 회전을 판별하려면 부호를 알아야 하는데, 어떻게 구해야 할까요?
벡터의 외적을 사용하면 두 벡터의 방향을 알 수 있습니다.
벡터의 외적이란 두 벡터 모두 수직인 벡터를 구하는 방식 입니다.
따라서 무조건 3차원의 그래프가 나오게 됩니다.
각도 값을 구하기 위해선 2차원의 구조로는 구할 수 없습니다.
따라서 각도의 +, -를 결정짓는 하나의 축이 더 필요로 한데,
이 때 두 벡터의 외적을 통해 나온 z축의 벡터가 +, -를 표현해 줄 것입니다.
val vectorTouchX=touchX-centerX
val vectorTOuchY=touchY-centerY
val vectorButtonX=buttonX-centerX
val vectorButtonY=buttonY-centerY
//외적으로 각도 방향 구함
//외적의 결과 값으로는 반시계 방향이 +, 시계 방향이 - 이다.
//하지만 안드로이드에서는 반시계 방향이 -, 시계 방향이 + 이다.
//따라서 음수를 넣어 반대로 설정한다.
val vectorProduct=-(vectorButtonX*vectorTOuchY-vectorButtonY*vectorTouchX)
val currDegree=Math.toDegrees(acos(cosA).toDouble()).toFloat()
if(vectorProduct<0){
//시계 방향
this.rotation += currDegree
}
else{
//반시계 방향
this.rotation-=currDegree
}이로서 회전 값을 모두 구할 수 있습니다.
