Source: Transform.js

/**
 * Transform Matrix
 * - 기본으로 상대 좌표로 계산한다
 * - getBoundary와 같은 특수한 경우만 절대좌표로 반환
 * - 나중에 IE filter로 사용할 때는 points에 절대좌표 기능을 넣어야 함
 * @namespace
 */
collie.Transform = {
    _htBoundary : {
        left : 0,
        top : 0,
        right : 0,
        bottom : 0
    },
    _bIsIEUnder8 : collie.util.getDeviceInfo().ie && collie.util.getDeviceInfo().ie < 9,
    
    /**
     * Transform된 표시 객체의 Boundary를 반환 한다 (0, 0에서 시작)
     * TODO Transform 상속 구현 안됨!
     * 
     * @param {collie.DisplayObject} oDisplayObject
     * @param {Boolean} bWithPoints 좌표를 반환하는지 여부, Sensor의 box hittest에서 쓰임
     * @return {Object} htResult 상대 좌표 영역
     * @return {Number} htResult.left
     * @return {Number} htResult.right
     * @return {Number} htResult.top
     * @return {Number} htResult.bottom
     * @return {Number} htResult.isTransform
     * @return {Number} htResult.points
     */
    getBoundary : function (oDisplayObject, bWithPoints) {
        var htInfo = oDisplayObject.get();
        var aPoints = [[0, 0], [htInfo.width, 0], [htInfo.width, htInfo.height], [0, htInfo.height]];
        var aTransformedPoints = this.points(oDisplayObject, aPoints);
        var htBoundary = collie.util.getBoundary(aTransformedPoints);
        this._htBoundary.left = htBoundary.left;
        this._htBoundary.right = htBoundary.right;
        this._htBoundary.bottom = htBoundary.bottom;
        this._htBoundary.top = htBoundary.top;
        this._htBoundary.isTransform = this.isUseTransform(oDisplayObject);
        
        if (bWithPoints) {
            this._htBoundary.points = aTransformedPoints; // sensor용 point
        }
        
        return this._htBoundary;
    },
    
    /**
     * 해당 표시 객체에 맞게 점들을 transform한 결과를 반환 한다
     * 
     * @param {collie.DisplayObject} oDisplayObject 대상 표시 객체
     * @param {Array} aPoints transform을 적용할 점들 (ex: [[x1, y1], [x2, y2], ...])
     */
    points : function (oDisplayObject, aPoints) {
        var aMatrix
        
        if (!this._bIsIEUnder8) {
            aMatrix = this.getMatrixRecusively(oDisplayObject);
        }

        // 계산할 필요가 없다면 그대로 반환
        if (!aMatrix) {
            return aPoints;
        }
        
        var aPointsAfter = [];
        
        for (var i = 0, len = aPoints.length; i < len; i++) {
            var htPoint = collie.Matrix.transform(aMatrix, aPoints[i][0], aPoints[i][1]);
            aPointsAfter.push([htPoint.x, htPoint.y]);
        }
        
        return aPointsAfter;
    },
    
    /**
     * 상속된 Transform을 적용한 Matrix를 반환
     * TODO 속도 체크해 봐야 함!
     * 
     * @param {collie.DisplayObject} oDisplayObject 최하위 객체
     * @return {Array} Matrix
     */
    getMatrixRecusively : function (oDisplayObject) {
        var self = oDisplayObject;
        var aMatrix = null;
        var nX = 0;
        var nY = 0;
        
        while (self) {
            if (this.isUseTransform(self)) {
                var aSelfMatrix = this.getMatrix(self, nX, nY);
                aMatrix = aMatrix !== null ? collie.Matrix.multiple(aMatrix, aSelfMatrix) : aSelfMatrix;
            }
            
            nX -= self._htOption.x;
            nY -= self._htOption.y;
            self = self.getParent();
        }
        
        return aMatrix;
    },
    
    /**
     * 대상 표시 객체에 맞는 Matrix를 구한다
     * 상대좌표의 matrix로 반환되며 최종 결과의 translate는 별도로 적용해야 한다
     * 
     * @param {collie.DisplayObject} oDisplayObject
     * @param {Number} nX 좌표 보정치
     * @param {Number} nY
     * @return {Array} Matrix
     */
    getMatrix : function (oDisplayObject, nX, nY) {
        if (typeof nX === "undefined") {
            nX = 0;
        }
        
        if (typeof nY === "undefined") {
            nY = 0;
        }
        
        var htOrigin = oDisplayObject.getOrigin();
        var htInfo = oDisplayObject.get();
        var aMatrix = collie.Matrix.translate(htOrigin.x + nX, htOrigin.y + nY);
        
        if (htInfo.angle !== 0) {
            aMatrix = collie.Matrix.multiple(aMatrix, collie.Matrix.rotate(htInfo.angle));
        }
        
        if (htInfo.scaleX !== 1 || htInfo.scaleY !== 1) {
            aMatrix = collie.Matrix.multiple(aMatrix, collie.Matrix.scale(htInfo.scaleX, htInfo.scaleY));
        }
        
        aMatrix = collie.Matrix.multiple(aMatrix, collie.Matrix.translate(-(htOrigin.x + nX), -(htOrigin.y + nY)));
        return aMatrix;
    },
    
    /**
     * Transform을 사용하고 있는 경우
     * @return {Boolean}
     */
    isUseTransform : function (oDisplayObject) {
        return (oDisplayObject._htOption.scaleX !== 1 || oDisplayObject._htOption.scaleY !== 1 || oDisplayObject._htOption.angle !== 0);
    }
};
comments powered by Disqus