path expressions


path expressions for After Effects TOC

Archimedean spiral path expression

// Archimedean spiral
var endsize = 540; //size on the outside 
var totalAngle = 360*2; // windings of the spiral in degrees
var anglecut = 10; // degrees on the winding between bezierpoints
var turn = 90; // angle of the spiral as a whole
var direction = -1; // 1 clockwise or -1 counterclockwise

var divisions = 360/anglecut ;
var pointsOnSpiral = ( Math.ceil(Math.abs(totalAngle/anglecut)) );
var totalAnglePart = totalAngle/(pointsOnSpiral);

function spiralLinePart(startAngle, totalAngle, endsize){
    var depthHereStart = linear(startAngle, 0, totalAngle, 0, endsize);
    var smallAngel = easeOut(startAngle, 0, 360, -1, -.125) ;
    if(endsize == 0){
        var spiralAngle = 0;
        } else {
        var spiralAngle = (Math.cos(totalAngle)/endsize + Math.PI*0.5) * smallAngel;
    }
    var mystart = degreesToRadians(startAngle + turn);

    // point
    var x = Math.sin(mystart) * depthHereStart;
    var y = -Math.cos(mystart) * depthHereStart * direction;
    var distance = length([0,0], [x, y]) / divisions * 2;
    var xt = .5 * ( distance * Math.cos(mystart) +  distance * Math.cos(mystart + spiralAngle) );
    var yt = .5 * ( distance * Math.sin(mystart) +  distance * Math.sin(mystart + spiralAngle) ) * direction;   

    var pointOne = [ [x,y], [-xt,-yt], [xt,yt] ];
    return [pointOne];
}

//pointAndTangents grouped as: point, inTangent, outTangent
var pointsAndTangents = [];
// draw spiral
var part = spiralLinePart(0, totalAngle, endsize);
pointsAndTangents.push( part[0] );
if(pointsOnSpiral <= 2){
    var part = spiralLinePart(0, totalAngle, endsize);
    pointsAndTangents.push( part[0] );
    }else{
    for(var i = 1;i < pointsOnSpiral; i++){
        var part = spiralLinePart(totalAnglePart*i, totalAngle, endsize);
        pointsAndTangents.push( part[0] );
    }
    var part = spiralLinePart(totalAnglePart*i, totalAngle, endsize);
    pointsAndTangents.push( part[0] );
}
// rearrange points and tangents
var myPoints = []; var myinTangents = []; var myoutTangents = [];
for(var i = 0;i<pointsOnSpiral+1;i++){
    myPoints.push(pointsAndTangents[i][0]);
    myinTangents.push(pointsAndTangents[i][1]);
    myoutTangents.push(pointsAndTangents[i][2]);
}
createPath(myPoints, myinTangents, myoutTangents, myIs_closed = false);

circle path expression

//full circle
var radiusx = 100;
var radiusy = 100;
var myPosition = [0,0] - radiusx;
var tanFactor =  1.104569499662;//8*(Math.sqrt(2)-1)/3 or 8/3*Math.tan(Math.PI/8)
var tanLengthx = (radiusy/2)  * tanFactor;
var tanLengthy = (radiusx/2)  * tanFactor;
var myPoints = [myPosition + [0,0], 
            myPosition + [radiusx, radiusy], 
            myPosition + [radiusx*2,0], 
            myPosition + [radiusx, -radiusy]    ];
var myinTangents = [[0, -tanLengthx],
                                    [-tanLengthy,0],
                                    [0, tanLengthx],
                                    [tanLengthy,0]];
var myoutTangents = [[0, tanLengthx],
                                    [tanLengthy,0],
                                    [0,-tanLengthx],
                                    [-tanLengthy,0]];
myIs_closed = true;
createPath(myPoints, myinTangents, myoutTangents, myIs_closed);

circle arc path expression

// circle arc path 
var mysize = 540; // radius of the circle
var totalAngle = 270; // arc of the cirlce in degrees
var myarc = 45; // degrees on the arc between bezierpoints, max 90 degrees
var turn = 45; // angle of the spiral as a whole
var direction = -1; // 1 clockwise or -1 counterclockwise

var anglecut = Math.min(myarc, 90);
var tanFactor = 1.104569499662 * anglecut/90;//8*(Math.sqrt(2)-1)/3 or 8/3*Math.tan(Math.PI/8)
var divisions = 360/anglecut ;
var pointsOnCircle = ( Math.ceil(Math.abs(totalAngle/anglecut)) );
var totalAnglePart = totalAngle/(pointsOnCircle);

function circleLinePart(startAngle, totalAngle, mysize){
    var mystart = degreesToRadians(startAngle + turn);
    // point
    var x = Math.sin(mystart) * mysize;
    var y = -Math.cos(mystart) * mysize * direction;
    var distance = mysize * tanFactor ;
    var xt = .5 * ( distance * Math.cos(mystart) );
    var yt = .5 * ( distance * Math.sin(mystart) * direction ); 

    var pointOne = [ [x,y], [-xt,-yt], [xt,yt] ];
    return [pointOne];
}

//pointAndTangents grouped as: point, inTangent, outTangent
var pointsAndTangents = [];
// draw circle
var part = circleLinePart(0, totalAngle, mysize);
pointsAndTangents.push( part[0] );
if(pointsOnCircle <= 2){
    var part = circleLinePart(0, totalAngle, mysize);
    pointsAndTangents.push( part[0] );
    }else{
    for(var i = 1;i < pointsOnCircle; i++){
        var part = circleLinePart(totalAnglePart*i, totalAngle, mysize);
        pointsAndTangents.push( part[0] );
    }
    var part = circleLinePart(totalAnglePart*i, totalAngle, mysize);
    pointsAndTangents.push( part[0] );
}
// rearrange points and tangents
var myPoints = []; var myinTangents = []; var myoutTangents = [];
for(var i = 0;i<pointsOnCircle+1;i++){
    myPoints.push(pointsAndTangents[i][0]);
    myinTangents.push(pointsAndTangents[i][1]);
    myoutTangents.push(pointsAndTangents[i][2]);
}
createPath(myPoints, myinTangents, myoutTangents, myIs_closed = false);

square path with per corner rounding {path4}

//rectangle to path with per corner rounding
var rectsize = [200,200];
var rectpos = [0,0];
var roundingBase = 75;
//per Corner values
var perCornerRounding = [-50, 0, -150, 0];

point1 = [-rectsize[0]/2 + rectpos[0], -rectsize[1]/2 + rectpos[1]];
point2 = [rectsize[0]/2 + rectpos[0], -rectsize[1]/2 + rectpos[1]];
point3 = [rectsize[0]/2 + rectpos[0], rectsize[1]/2 + rectpos[1]];
point4 = [-rectsize[0]/2 + rectpos[0], rectsize[1]/2 + rectpos[1]];

mypt = [point1, point2, point3, point4];
myit = [[0,0], [0,0], [0,0], [0,0]];
myot = [[0,0], [0,0], [0,0], [0,0]];
mylength = mypt.length;
myopenclose = true;

//throw new Error(perCornerRounding)
roundCorner = 0.5519;

newpt = [];
newit = [];
newot = [];
for(var i=0;i<mylength;i++){
    rounding = roundingBase + perCornerRounding[i];
    currentV = mypt[i];
    currentO = myot[i] + mypt[i];
    currentI = myit[i] + mypt[i];
    if (currentV[0] === currentO[0] && currentV[1] === currentO[1] && currentV[0] === currentI[0] && currentV[1] === currentI[1]) {
        if ((i === 0 || i === mylength - 1) && !myopenclose) {
            newpt.push(currentV);
            newit.push(currentI - currentV);
            newot.push(currentO - currentV);
        } else {
            if (i === 0) {
                closerV = mypt[mylength - 1];
                closerO = myot[mylength - 1] + closerV;
                closerI = myit[mylength - 1] + closerV;
            } else {
                closerV = mypt[i - 1];
                closerO = myot[i - 1] + closerV;
                closerI = myit[i - 1] + closerV;
            }
            if (closerV[0] === closerO[0] && closerV[1] === closerO[1]) {
                distance =  Math.sqrt(Math.pow(currentV[0] - closerV[0], 2) 
                            + Math.pow(currentV[1] - closerV[1], 2));
                newPosPerc = distance ? Math.min(distance / 2, rounding) / distance : 0;
                iX = currentV[0] + (closerV[0] - currentV[0]) * newPosPerc;
                vX = iX;
                iY = currentV[1] - (currentV[1] - closerV[1]) * newPosPerc;
                vY = iY;
            } else {
                distance =  Math.sqrt(Math.pow(currentV[0] - (closerO[0]), 2) 
                            + Math.pow(currentV[1] - (closerO[1]), 2));
                newPosPerc = distance ? Math.min(distance, rounding) / distance : 0;
                iX = currentV[0] + ((closerO[0]) - currentV[0]) * newPosPerc;
                vX = iX;
                iY = currentV[1] - (currentV[1] - (closerO[1])) * newPosPerc;
                vY = iY;
            }
            oX = vX - (vX - currentV[0]) * roundCorner;
            oY = vY - (vY - currentV[1]) * roundCorner;

            newpt.push([vX,vY]);
            newit.push([iX,iY] - [vX,vY]);
            newot.push([oX,oY] - [vX,vY]);

            if (i === mylength - 1) {
                closerV = mypt[0];
                closerO = myot[0] + closerV;
                closerI = myit[0] + closerV;
            } else {
                closerV = mypt[i + 1];
                closerO = myot[i + 1] + closerV;
                closerI = myit[i + 1] + closerV;
            }
            if (closerV[0] === closerI[0] && closerV[1] === closerI[1]){
                distance =    Math.sqrt(Math.pow(currentV[0] - closerV[0], 2) 
                            + Math.pow(currentV[1] - closerV[1], 2));
                newPosPerc = distance ? Math.min(distance / 2, rounding) / distance : 0;
                oX = currentV[0] + (closerV[0] - currentV[0]) * newPosPerc;
                vX = oX;
                oY = currentV[1] - (currentV[1] - closerV[1]) * newPosPerc;
                vY = oY;
            } else {
                distance = Math.sqrt(Math.pow(currentV[0] - (closerI[0]), 2) + Math.pow(currentV[1] - (closerI[1]), 2));
                newPosPerc = distance ? Math.min(distance , rounding) / distance: 0;
                oX = currentV[0] + ((closerI[0]) - currentV[0]) * newPosPerc;
                vX = oX;
                oY = currentV[1] - (currentV[1] - (closerI[1])) * newPosPerc;
                vY = oY;
            }
            iX = vX - (vX - currentV[0]) * roundCorner;
            iY = vY - (vY - currentV[1]) * roundCorner;

            newpt.push([vX,vY]);
            newit.push([iX,iY] - [vX,vY]);
            newot.push([oX,oY] - [vX,vY]);
        }
    } else {
        newpt.push(currentV);
        newit.push(currentI - currentV);
        newot.push(currentO - currentV);
    } 
}

createPath(newpt, newit, newot, myopenclose);