
var shapeAnchorName = "{{shapeAnchorName}}";
var latPropName = "{{latPropName}}";
var lonPropName = "{{lonPropName}}";
var rotateWithMapPropName = "{{rotateWithMapPropName}}";
var rotateAlongPathPropName = "{{rotateAlongPathPropName}}";
var bearingOffsetPropName = "{{bearingOffsetPropName}}";
var positionProgressPropName = "{{positionProgressPropName}}";
var mapSize = {{globalMapSize}};

var smoothing = {{smoothing}};//a value between 0 and 1 describing the smoothness of the rotation


var bearing = 0
try{var rotateWithMap = effect(rotateWithMapPropName).param(1).value}catch(e){var rotateWithMap = false}
try{var rotateAlongPath = effect(rotateAlongPathPropName).param(1).value}catch(e){var rotateAlongPath = false}
try{var bearingOffset = effect(bearingOffsetPropName).param(1).value}catch(e){var bearingOffset = 0}

if(rotateWithMap){
    if(rotateAlongPath){
        var Clip = function(n, minValue, maxValue) {
                return Math.min(Math.max(n, minValue), maxValue);
        }
        var LatToPixelY = function(latitude){
            var min_lat= -85.05112878;
            var max_lat= 85.05112878;
            latitude = Clip(latitude, min_lat, max_lat);
            var sinLatitude = Math.sin(latitude * Math.PI / 180);
            var y = 0.5 - Math.log((1 + sinLatitude) / (1 - sinLatitude)) / (4 * Math.PI);
            var pixelY = y * mapSize /*+ 0.5*/;
            pixelY = Clip(pixelY, 0, mapSize - 1);
            return pixelY
        }
        var LonToPixelX = function(longitude){
            var x = (longitude + 180) / 360;
            var pixelX = x * mapSize /*+ 0.5*/;
            return pixelX
        }
        var getValueByProgressOrAtTime = function(prop, t){
            if(progressProp && progressEff.active && (progressTMax !== null && progressTMin !== null)){
                return prop.valueAtTime(linear(progressProp.valueAtTime(t), 0, 100, progressTMin, progressTMax))
            }else{
                return prop.valueAtTime(t)
            }
        }
        var getDirectionVec = function(effectLat, effectLon, t1, t2){
            var latLon1= [getValueByProgressOrAtTime(effectLat, t1), getValueByProgressOrAtTime(effectLon, t1)];
            var latLon2= [getValueByProgressOrAtTime(effectLat, t2), getValueByProgressOrAtTime(effectLon, t2)];
            var p1 = [LonToPixelX(latLon1[1]), LatToPixelY(latLon1[0])]
            var p2 = [LonToPixelX(latLon2[1]), LatToPixelY(latLon2[0])]
            return p2-p1;
        }
        var getPreviousKeyIndex = function(prop){
            var nearestKey = prop.nearestKey(time)
            var previousKeyIndex = nearestKey.index;
            if(nearestKey.time > time){
                previousKeyIndex --
            }
            return previousKeyIndex
        }

        var effectLat = effect(latPropName).param(1);
        var effectLon = effect(lonPropName).param(1);
        try{
            var progressEff = effect(positionProgressPropName);
            var progressProp = progressEff.param(1);
        }catch(e){
            var progressProp = null
        }
        if(progressProp && progressEff.active && (effectLat.numKeys > 1 || effectLon.numKeys > 1 || pxHeightProp.numKeys > 1)){
            var progressTMin = Math.min(effectLat.numKeys?effectLat.key(1).time:Infinity, effectLon.numKeys?effectLon.key(1).time:Infinity);
            var progressTMax = Math.max(effectLat.numKeys?effectLat.key(effectLat.numKeys).time:-Infinity, effectLon.numKeys?effectLon.key(effectLon.numKeys).time:-Infinity);
        }else{
            var progressTMin, progressTMax = null;
        }
        if(effectLat.numKeys > 1 && effectLon.numKeys > 1){
            var v = getDirectionVec(effectLat, effectLon, time-smoothing/2, time+framesToTime(1)+smoothing/2)

            if(v[0] == 0 && v[1] == 0){
                var previousKeyIndex = getPreviousKeyIndex(effectLat)
                if(previousKeyIndex>0){
                    var previousKeyTime = effectLat.key(previousKeyIndex).time
                    v = getDirectionVec(effectLat, effectLon, previousKeyTime-0.01, previousKeyTime)
                }else{
                    var nextKeyTime = effectLat.key(previousKeyIndex+1).time
                    v = getDirectionVec(effectLat, effectLon, nextKeyTime, nextKeyTime+0.01)
                }
            }
            bearing = radiansToDegrees(Math.atan2(v[1], v[0]));
        }
    }
    var shapeAnchorLayer = thisComp.layer(shapeAnchorName)
    if(thisLayer.hasParent && thisLayer.parent == shapeAnchorLayer){
        var orient = [value[0], value[1], value[2] + bearing]
    }else{
        if(thisLayer.transform.scale[0] > 0 && thisLayer.transform.scale[1] > 0 || thisLayer.transform.scale[2] > 0){
            var vecU = shapeAnchorLayer.toWorldVec([1,0,0]);
            var vecV = shapeAnchorLayer.toWorldVec([0,1,0]);
            var vecW = normalize(shapeAnchorLayer.toWorldVec([0,0,1]));

            var sinb = clamp(vecW[0],-1,1);
            var b = Math.asin(sinb);
            var cosb = Math.cos(b);

            if (Math.abs(cosb) > .0005){
                var c = -Math.atan2(vecV[0],vecU[0]);
                var a = -Math.atan2(vecW[1],vecW[2]);
            }else{
                var a = (sinb < 0 ? -1 : 1)*Math.atan2(vecU[1],vecV[1]);
                var c = 0;
            }

            var orient = [radiansToDegrees(a),radiansToDegrees(b),radiansToDegrees(c) + bearing + bearingOffset]
        }else{
            var orient = [0,0,0]
        }
    }

    orient
}else{
    value
}
