반응형
블로그 이미지
개발자로서 현장에서 일하면서 새로 접하는 기술들이나 알게된 정보 등을 정리하기 위한 블로그입니다. 운 좋게 미국에서 큰 회사들의 프로젝트에서 컬설턴트로 일하고 있어서 새로운 기술들을 접할 기회가 많이 있습니다. 미국의 IT 프로젝트에서 사용되는 툴들에 대해 많은 분들과 정보를 공유하고 싶습니다.
솔웅

최근에 받은 트랙백

글 보관함

Pinch Zoom Rotate 구현하기 - 8/11 -

2013. 2. 13. 15:14 | Posted by 솔웅


Posted on . Written by


Scaling

display object를 멀티 터치로 컨트롤 하면서 우리가 원하는 transformation을 적용하려면 모든 tracking dot들의 평균 값들이 필요합니다. 그리고 그 값을 display object의 midpoint (그 평균 위치) 에 이미지를 위치시켜야 합니다.


scaling 과 관련해서는 수학적인 계산이 필요합니다.

    midpoint 와 tracking dot들 간의 거리의 합 구하기
    거리의 합계를 dot 들의 갯수로 나눈 평균 거리 구하기
    tracking dot 들의 이전 위치에 대한 같은 평균 거리 구하기
    이전과 현재의 평균 거리 사이의 차이 구하기
    display object 의 .xScale 과 .yScale에  multiplication 으로 그 차이를 적용하기


이건 여러 tracking dot들이 움직일 때 display object 의 평균 transition 을 어떻게 적용할 지를 정해 주는 겁니다. 이 scaling 값을 얻도록 하는 기본 라이브러리 함수들을 만들 겁니다. 아래 함수는 스크린의 두개의 지점사이의 거리를 계산하는 함수입니다. 아주 전형적인 삼각함수죠.

sample8.lua

-- returns the distance between points a and b
function lengthOf( a, b )
local width, height = b.x-a.x, b.y-a.y
return (width*width + height*height)^0.5
end


tracking dot들의 midpoint 를 얻기 위해 sample 5 에서 다뤘던  calcAvgCentre() 함수를 사용할 겁니다.  midpoint 와 tracking dot 들 사이의 평균 거리를 구해서 저장하기 위해 다음과 같은 함수들을 사용할 겁니다. 첫번째는 각 dot 들의 현재 distance 를 get 해서 그 값을 tracking dot 에 저장할 겁니다. 그리고 이전 distance 도 물론 저장하구요. 두번째 함수에서는 이전과 현재 거리 set 들 사이의 차이를 계산하는 함수를 사용할 겁니다.


-- calculate each tracking dot's distance from the midpoint
local function updateTracking( centre, points )
for i=1, #points do
local point = points[i]
point.prevDistance = point.distance
point.distance = lengthOf( centre, point )
end
end
 
-- calculates scaling amount based on the average change in tracking point distances
local function calcAverageScaling( points )
local total = 0
for i=1, #points do
local point = points[i]
total = total + point.distance / point.prevDistance
end
return total / #points
end

이 함수를 사용하는 방법은 간단합니다. rect:touch()의 began 과 ended phase 에서 call 하시면 됩니다. 그러면 이 함수들이 적당한 값으로 해당 tracking dot 들의 값을 update 할 겁니다. 아래는 began 과 ended phase 에서 call 하는 부분입니다.


-- "began"
-- pre-store the tracking dot scale and rotation values
updateTracking( rect.prevCentre, rect.dots )
return true -- we handled the began phase
 
-- "ended"
-- store the new centre of all touch points
rect.prevCentre = calcAvgCentre( rect.dots )
-- refresh tracking dot scale and rotation values
updateTracking( rect.prevCentre, rect.dots )

moved phase 는 조금 더 복잡합니다. 왜냐하면 실제 이 부분에서 대부분의 일이 진행 될 거거든요. 다행히 여기서 우리가 해야 될 일은 tracking dot 을 update 하는 똑 같은 일에다가 tracking dot 이 한개 이상일 경우 scaling 을 적용하는 일 뿐입니다.


if (e.phase == "moved") then
print( e.phase, e.x, e.y )
local centre, scale, rotate = {}, 1, 0 -- declare working variables
centre = calcAvgCentre( rect.dots ) -- calculate the average centre position of all touch points
updateTracking( rect.prevCentre, rect.dots ) -- refresh tracking dot scale and rotation values
-- if there is more than one tracking dot, calculate the rotation and scaling
if (#rect.dots > 1) then
scale = calcAverageScaling( rect.dots ) -- calculate the average scaling of the tracking dots
rect.xScale, rect.yScale = rect.xScale * scale, rect.yScale * scale -- apply scaling to rect
end
rect.x = rect.x + (centre.x - rect.prevCentre.x) -- update the X position of rect
rect.y = rect.y + (centre.y - rect.prevCentre.y) -- update the Y position of rect
rect.prevCentre = centre -- store the centre of all touch points
else -- "ended" and "cancelled" phases

main.lua

sample8.lua


위에서 moved phase 에서 우리가 바꾼 부분은 아래와 같습니다.

    앞으로 일어날 transformation 값들과 같이 사용될 변수들 정의
    tracking dot 들의 저장된 distance 값을 refresh 하기 위해 updateTracking 을 call 하기
    tracking scaling 에서 변한 값의 평균을 구하기 위해 distance 값들 사용하기
    display object "rect" 에 해당 scaling 적용하기

The display object now translates (moves) and scales (zooms) along with our tracking dots (touch points).
이제 이 display object 는 tracking dot 들 (touch point 들) 의 움직임에 따라 translates (moves) 과  scales (zooms) 를 하게 됐습니다.

반응형

Comment