path expressions
path expressions for After Effects TOC
- Archimedean spiral path expression
A reasonably fast bezier path expression for a spiral. It's not perfect, but if a true after effects mathematician comes along: Please help me out here! 🙂 - circle path expression
full circle path expression. - circle arc path expression
Arc of a circle path with possibly more bezierpoints. - square path with per corner rounding
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);